original files of m241
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,656 @@
|
||||
/* ipdiameter_client.c - Library of Diameter client user authentication */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement. No license to Wind River intellectual property rights
|
||||
* is granted herein. All rights not licensed by Wind River are reserved
|
||||
* by Wind River.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01m,23nov10,hfc fir buildwarning.Defect WIND00242868
|
||||
01l,10mar09,tlu Fix Linux build warning
|
||||
01k,12feb09,tlu Enforce reservered flag bits must be zeor in a pkt header
|
||||
01j,14jan09,tlu Remove adding destination host AVP
|
||||
01i,07sep07,tlu Modify file name comment for apigen
|
||||
01h,16aug07,tlu Add Diameter MIP4 HAR callback registration/de-registration
|
||||
functions for MIP4 to receive incoming HAR messages
|
||||
01g,01aug07,tlu Add client open function
|
||||
01f,16jul07,tlu Add application API comment blocks for apigen
|
||||
01e,10jul07,tlu Update after code inspection
|
||||
01d,03jul07,tlu Insert User Password AVP
|
||||
01c,21jun07,tlu More AVP checking and adding if AVPs are missing
|
||||
01b,20jun07,tlu Add test code for Open diameter testing
|
||||
01a,05apr07,tlu Created.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This library provides routines for Diameter client user authentication.
|
||||
|
||||
To use this feature, include the following component: INCLUDE_IPDIAMETERC
|
||||
|
||||
INCLUDE FILES: ipdiameter.h, ipdiameter_client.h, ipdiameter_config.h
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* DESCRIPTION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* CONFIGURATION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#include "ipdiameter_config.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
|
||||
/* ipcom */
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_cstyle.h>
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_os.h>
|
||||
#include <ipcom_err.h>
|
||||
#include <ipcom_sysvar.h>
|
||||
#include <ipcom_syslog.h>
|
||||
|
||||
|
||||
/* ipdiameter */
|
||||
#include "ipdiameter.h"
|
||||
#include "ipdiameter_client.h"
|
||||
|
||||
|
||||
/*
|
||||
**************************************************************************
|
||||
* DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define IPDIAMETERC_PROC "ipdiametercd"
|
||||
|
||||
|
||||
/* This is a compile flag, turning on it will build debug message into image */
|
||||
#undef DIAMETER_DEBUG
|
||||
|
||||
/* This is a compile flag, turn on for Open Diameter testing */
|
||||
/* #undef OPEN_DIAMETER_TEST */
|
||||
|
||||
#ifdef OPEN_DIAMETER_TEST
|
||||
#undef IPDIAMETER_VALID_APP_ID
|
||||
#define IPDIAMETER_VALID_APP_ID(id) ((id == DIAMETER_Common_Message) || \
|
||||
(id == DIAMETER_NASREQ) || \
|
||||
(id == DIAMETER_MIP) || \
|
||||
(id == DIAMETER_Base_Accounting) || \
|
||||
(id == DIAMETER_Credit_Control) || \
|
||||
(id == DIAMETER_Relay) || \
|
||||
(id == DIAMETER_EAP) || \
|
||||
(id == 10000))
|
||||
#endif /* OPEN_DIAMETER_TEST */
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IP_EXTERN Ipdiameter_data ipdiameter;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ipdiameter_access_request - handle a user request
|
||||
*
|
||||
* This routine performs validation checking on the user authentication request,
|
||||
* create a auth session for the first packet in a session, selects the server
|
||||
* associated with the session, and hand the request to auth session finite
|
||||
* state machine to transmit a DIAMETER request to the DIAMETER server.
|
||||
*
|
||||
* Diameter client takes over the ownership of the passed-in Diameter packet,
|
||||
* the caller must NOT free or modify the packet. If any error value is
|
||||
* returned, the passed-in Diameter packet is freed immediately; otherwise
|
||||
* the packet will be freed upon receving an answer back.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <packet>
|
||||
* A Diameter request packet of type Ipdiameter_header; expect a Diameter
|
||||
* packet allocated by ipdiameter_request_pkt_malloc().
|
||||
* \i <request>
|
||||
* A user request structure of type Ipdiameter_request.
|
||||
* \i <errattr>
|
||||
* A flag indicates wheter any AVP in the passed-in Diameter packet is in wrong
|
||||
* format.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS:
|
||||
* \is
|
||||
* \i IPCOM_SUCCESS
|
||||
* \i IPCOM_ERR_INVALID_ARG if any passed-in argument is invalid
|
||||
* \i IPCOM_ERR_NOT_OPENED if Diameter client is not opened
|
||||
* \i IPCOM_ERR_NO_MEMORY if memory allocation failed
|
||||
* \i IPCOM_ERR_PENDING if an identical request is already pending
|
||||
* \i IPDIAMETER_ERR_INVAL_PWD_TYPE if wrong password type in request structure
|
||||
* \ie
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
*/
|
||||
|
||||
IP_PUBLIC Ip_err ipdiameter_access_request
|
||||
(
|
||||
Ipdiameter_header *packet,
|
||||
Ipdiameter_request *request,
|
||||
Ip_u8 *errattr
|
||||
)
|
||||
{
|
||||
Ipdiameter_request_entry *reqent;
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
Ip_u8 *pek;
|
||||
Ip_u32 command_code;
|
||||
Ipdiameter_session *session = IP_NULL;
|
||||
Ip_bool new_session = IP_FALSE;
|
||||
Ip_u32 length;
|
||||
Ip_u8 *data;
|
||||
Ipdiameter_server *server;
|
||||
|
||||
|
||||
if (errattr)
|
||||
*errattr = 0;
|
||||
|
||||
if (packet == IP_NULL)
|
||||
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_ARG);
|
||||
|
||||
/* Step back to get request entry pointer. */
|
||||
pek = (Ip_u8 *)packet;
|
||||
pek += sizeof(Ipdiameter_header);
|
||||
pek -= sizeof(Ipdiameter_request_entry);
|
||||
reqent = (Ipdiameter_request_entry *)pek;
|
||||
|
||||
/* Diameter client is not opened. */
|
||||
if (ipdiameter.opened == IP_FALSE)
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_NOT_OPENED);
|
||||
|
||||
/* Mark a user request */
|
||||
reqent->user_request = IP_TRUE;
|
||||
|
||||
/* Clear and set request entry data. */
|
||||
ipdiameter_reqent_copy_req(reqent, request);
|
||||
|
||||
/* Find out whether there is an existing session associated with the request */
|
||||
session = ipdiameter_find_session(request->session_id);
|
||||
|
||||
if (session == IP_NULL)
|
||||
{
|
||||
if ((request->num_servers > IPDIAMETER_MAX_SPECIFIED_SERVERS) ||
|
||||
(request->num_servers < 1) ||
|
||||
(request->selected_server > request->num_servers - 1) ||
|
||||
(request->selected_server < -1))
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_access_request: invalid server list\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_INVALID_ARG);
|
||||
}
|
||||
|
||||
/* no existing session of the same session id, create a new session */
|
||||
session = ipdiameter_create_session((struct Ipdiameter_request_entry *) reqent);
|
||||
if (session != IP_NULL) new_session = IP_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
reqent->session = session;
|
||||
|
||||
/* Check if identical request is pending. */
|
||||
if (ipdiameter_check_request_pending(reqent) == IP_TRUE)
|
||||
{
|
||||
/* The same request has been requested already */
|
||||
IPCOM_LOG0(ERR, "ipdiameter_access_request: same request is pending already\n");
|
||||
IPDIAMETER_LEAVE(IPCOM_ERR_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
if (session != IP_NULL)
|
||||
{
|
||||
/* Insert request into session's request list. */
|
||||
ipdiameter_session_add_req(session, (struct Ipdiameter_header *)packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_access_request, failed to open a session\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Take session's server */
|
||||
server = (Ipdiameter_server *)session->serv_list[session->selected_server];
|
||||
|
||||
|
||||
/* Set hop-by-hop and end-to-end IDs in packet header by unique value in request */
|
||||
reqent->hdr.hbh_id = (Ip_u32)ip_htonl(request->unique);
|
||||
reqent->hdr.e2e_id = reqent->hdr.hbh_id;
|
||||
reqent->hdr.appl_id = (Ip_u32)ip_htonl(request->appl_id);
|
||||
|
||||
/* validate the packet's version, flags, and command code */
|
||||
command_code = ipdiameter_get_hdr_code((Ip_u32 *)packet);
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_access_request, packet code: %lu, flags:%x, appl_id %lu\n",
|
||||
command_code, packet->flags, request->appl_id);
|
||||
#endif
|
||||
|
||||
/* Check the packet header */
|
||||
if ((packet->version != IPDIAMETER_VERSION) ||
|
||||
((packet->flags & IPDIAMETER_R_FLAG) == 0) ||
|
||||
((packet->flags & IPDIAMETER_RES_FLAG) != 0) ||
|
||||
!(IPDIAMETER_VALID_APP_ID(request->appl_id)) ||
|
||||
!(IPDIAMETER_VALID_COMMAND_CODE((Ip_s32)command_code)))
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_access_request: invalid packet header\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_INVALID_ARG);
|
||||
}
|
||||
|
||||
/* Check for event callback function not NULL */
|
||||
if (request->event_callback == IP_NULL)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_access_request: MUST specify event_callback function\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_INVALID_ARG);
|
||||
}
|
||||
|
||||
/*
|
||||
* If an access request,
|
||||
* fill in NAS identifier AVP if not filled already
|
||||
* fill in Auth Application Id AVP if not filled already
|
||||
*/
|
||||
if (command_code == IPRADIUS_CODE_Access_Request)
|
||||
{
|
||||
retval = ipdiameter_get_avp(packet, RADIUS_ATTR_NAS_Identifier, &length, &data);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
/* Add NAS Identifier AVP */
|
||||
ipdiameter_avp_add_NAS_identifier(packet);
|
||||
|
||||
retval = ipdiameter_get_avp(packet, DIAMETER_AVP_CODE_Auth_Application_Id,
|
||||
&length, &data);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
/* Add Auth_Application_Id AVP */
|
||||
(void)ipdiameter_avp_add_u32(packet, DIAMETER_AVP_CODE_Auth_Application_Id,
|
||||
DIAMETER_AVP_M_FLAG, IP_NULL, request->appl_id);
|
||||
}
|
||||
|
||||
/* Add Destination Realm AVP if not in the packet already */
|
||||
retval = ipdiameter_get_avp(packet, DIAMETER_AVP_CODE_Destination_Realm,
|
||||
&length, &data);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
/* Add Destination-Realm AVP */
|
||||
length = (Ip_u32)ipcom_strlen(server->realm);
|
||||
if (length != 0)
|
||||
(void)ipdiameter_avp_add_array(&(reqent->hdr),
|
||||
DIAMETER_AVP_CODE_Destination_Realm, DIAMETER_AVP_M_FLAG,
|
||||
IP_NULL, (Ip_u8 *)server->realm, length);
|
||||
}
|
||||
|
||||
/* Check request password length if there. */
|
||||
switch(request->pwd_type)
|
||||
{
|
||||
case IPDIAMETER_CHAP_Password:
|
||||
retval = ipdiameter_get_avp(packet, RADIUS_ATTR_CHAP_Challenge, &length, &data);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPDIAMETER_ERROUT(IPDIAMETER_ERR_MISSING_CHAP_ATTR);
|
||||
|
||||
if (length < 7)
|
||||
IPDIAMETER_ERROUT(IPDIAMETER_ERR_INVAL_PWD_LEN);
|
||||
|
||||
retval = ipdiameter_get_avp(packet, RADIUS_ATTR_CHAP_Password, &length, &data);
|
||||
if (retval == IPCOM_SUCCESS)
|
||||
;/* Chap password already filled */
|
||||
else if (command_code == IPRADIUS_CODE_Access_Request ||
|
||||
command_code == DIAMETER_CODE_AA_Mobile_Node_Request)
|
||||
/* fill in CHAP password */
|
||||
ipdiameter_password_insert(reqent);
|
||||
|
||||
break;
|
||||
|
||||
case IPDIAMETER_PAP_Password:
|
||||
if (request->pwd_len > IPDIAMETER_MAX_PASSWORD_SIZE || request->pwd_len == 0)
|
||||
{
|
||||
badpwdlen:
|
||||
IPDIAMETER_ERROUT(IPDIAMETER_ERR_INVAL_PWD_LEN);
|
||||
}
|
||||
|
||||
retval = ipdiameter_get_avp(packet, RADIUS_ATTR_User_Password, &length, &data);
|
||||
if (retval == IPCOM_SUCCESS)
|
||||
;/* PAP password already filled */
|
||||
else if (command_code == IPRADIUS_CODE_Access_Request ||
|
||||
command_code == DIAMETER_CODE_AA_Mobile_Node_Request)
|
||||
/* fill in PAP password */
|
||||
ipdiameter_password_insert(reqent);
|
||||
|
||||
break;
|
||||
|
||||
case IPDIAMETER_No_Password:
|
||||
if (request->pwd_len != 0)
|
||||
goto badpwdlen;
|
||||
break;
|
||||
|
||||
default:
|
||||
IPDIAMETER_ERROUT(IPDIAMETER_ERR_INVAL_PWD_TYPE);
|
||||
}
|
||||
|
||||
/* Add EAP message authenticator if missing */
|
||||
if ( (command_code == IPRADIUS_CODE_Access_Request)
|
||||
&& (ipdiameter_get_avp(packet, RADIUS_ATTR_EAP_Message, &length, &data)
|
||||
== IPCOM_ERR_NOT_FOUND)
|
||||
&& (ipdiameter_get_avp(packet, RADIUS_ATTR_Message_Authenticator,
|
||||
&length, &data) == IPCOM_ERR_NOT_FOUND))
|
||||
ipdiameter_attr_add_message_auth(reqent);
|
||||
|
||||
|
||||
/* perform error checking on user's AVPs */
|
||||
retval = ipdiameter_avp_check(&reqent->hdr, reqent, errattr);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_access_request, failed in AVP checking\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* packet will be sent out from session FSM */
|
||||
retval = ipdiameter_client_auth_fsm(session,
|
||||
(struct Ipdiameter_header *)packet,
|
||||
DIAMETER_CLIENT_AUTH_EV_ACCESS_REQ);
|
||||
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipdiameter_access_request, session FSM returns error %d\n", retval);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
IPDIAMETER_LEAVE(IPCOM_SUCCESS);
|
||||
|
||||
errout:
|
||||
/* free reqent. */
|
||||
if (reqent) ipdiameter_reqent_free(reqent);
|
||||
|
||||
/* free session */
|
||||
if (new_session) ipdiameter_delete_session(session);
|
||||
|
||||
leave:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ipdiameter_register_access_function - register a user callback function
|
||||
*
|
||||
* This routine allows an application to register a specific callback function
|
||||
* associated with an incoming Diameter request packet. When Diameter client
|
||||
* receives an incoming Diameter request package with the specified command
|
||||
* code, the registered callback function will be invoked, the received
|
||||
* package, the peer to receive the package from, and the registered opaque
|
||||
* callback data will be passed to the application.
|
||||
*
|
||||
* Note that the peer structure is pssed to an application so that the
|
||||
* application knows where the packet comes from and where to send the reply.
|
||||
* Applications must NOT modify any fields in the peer structure.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <code>
|
||||
* Diameter command code.
|
||||
* \i <callback>
|
||||
* A callback function to be invoked.
|
||||
* \i <opaque_callback_data>
|
||||
* An opaque callback data allocated by the application.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
*/
|
||||
void ipdiameter_register_access_function
|
||||
(
|
||||
Ip_u32 code,
|
||||
void (*callback) (Ip_u32 code,
|
||||
Ipdiameter_header *packet,
|
||||
Ipdiameter_peer_entry *peer,
|
||||
void *opaque_callback_data),
|
||||
void *opaque_callback_data
|
||||
)
|
||||
{
|
||||
/* Diameter client is not opened. */
|
||||
if (ipdiameter.opened == IP_FALSE)
|
||||
return;
|
||||
|
||||
IPDIAMETER_LOCK();
|
||||
|
||||
ipdiameter.user_callback = callback;
|
||||
ipdiameter.opaque_callback_data = opaque_callback_data;
|
||||
|
||||
IPDIAMETER_UNLOCK();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ipdiameter_deregister_access_function - deregister a user callback function
|
||||
*
|
||||
* This routine allows an application to deregister a callback function
|
||||
* associated with a Diameter command code. The registered opaque callback
|
||||
* data will be freed.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* \is
|
||||
* \i <code>
|
||||
* Diameter command code.
|
||||
* \ie
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO: N/A
|
||||
*
|
||||
*/
|
||||
void ipdiameter_deregister_access_function
|
||||
(
|
||||
Ip_u32 code
|
||||
)
|
||||
{
|
||||
/* Diameter client is not opened. */
|
||||
if (ipdiameter.opened == IP_FALSE)
|
||||
return;
|
||||
|
||||
IPDIAMETER_LOCK();
|
||||
|
||||
ipdiameter.user_callback = IP_NULL;
|
||||
|
||||
if (ipdiameter.opaque_callback_data)
|
||||
ipcom_free(ipdiameter.opaque_callback_data);
|
||||
ipdiameter.opaque_callback_data = IP_NULL;
|
||||
|
||||
IPDIAMETER_UNLOCK();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterc_create
|
||||
*===========================================================================
|
||||
* Description: Initialize global IPDIAMETER data 'ipdiameter'.
|
||||
* Parameters: .
|
||||
* Returns: .
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterc_create(void)
|
||||
{
|
||||
Ip_err ret_val = IPCOM_SUCCESS;
|
||||
|
||||
ret_val = ipdiameter_common_create(DIAMETER_PEER_CLIENT);
|
||||
|
||||
/* Initialize close and exit functions */
|
||||
ipdiameter.close = ipdiameterc_close;
|
||||
ipdiameter.exit = ipdiameterc_exit;
|
||||
ipdiameter.open = ipdiameterc_open;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterc_close
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterc_close(void)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
|
||||
retval = ipdiameter_common_close();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterc_exit
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterc_exit(void)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
|
||||
retval = ipdiameter_common_exit();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterc_open
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterc_open(void)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
|
||||
IPDIAMETER_LOCK();
|
||||
|
||||
/** Get IPDIAMETER client specific configuration parameters **/
|
||||
|
||||
/* Get diameter ASR comply configuration */
|
||||
ipdiameter.ASR_comply = ipcom_sysvar_get_as_int("ipdiameter.asrcomply", -1);
|
||||
if ((ipdiameter.ASR_comply != 0) && (ipdiameter.ASR_comply != 1))
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_common_open: wrong config parameter DIAMETER_ASR_COMPLY\n");
|
||||
IPDIAMETER_LEAVE(IPCOM_ERR_INVALID_CONFIG);
|
||||
}
|
||||
|
||||
/* Get diameter session timeout in seconds */
|
||||
ipdiameter.session_timeout = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.timeout.session", -1);
|
||||
|
||||
/* Get diameter authorization lifetime in seconds */
|
||||
ipdiameter.auth_lifetime = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.timeout.authlifetime", -1);
|
||||
|
||||
/* Get diameter auth grace period in seconds */
|
||||
ipdiameter.auth_grace_period = (Ip_u16)ipcom_sysvar_get_as_int("ipdiameter.timeout.authgraceperiod", -1);
|
||||
|
||||
|
||||
leave:
|
||||
IPDIAMETER_UNLOCK();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterc_start
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterc_start(void)
|
||||
{
|
||||
Ip_err ret = IPCOM_SUCCESS;
|
||||
|
||||
ret = ipdiameter_common_start(IPDIAMETERC_PROC);
|
||||
if (ret != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameterc_start: Failed on ipdiameter_common_start");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterc_stop
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterc_stop(void)
|
||||
{
|
||||
Ip_err ret = IPCOM_SUCCESS;
|
||||
|
||||
ret = ipdiameter_common_stop();
|
||||
if (ret != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameterc_stop: Failed on ipdiameter_common_stop");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
/* ipdiameter_client_auth_session_fsm.c - IPNet Diameter client authentication session FSM file */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement. No license to Wind River intellectual property rights
|
||||
* is granted herein. All rights not licensed by Wind River are reserved
|
||||
* by Wind River.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01f,31mar09,tlu Add RAR to stateful FSM
|
||||
01e,13aug07,tlu Modify ipdiameter_send_ASA() parameter to add TLS support
|
||||
01d,05jul07,tlu Replace ipcom_printf by IPCOM_LOG
|
||||
01c,26jun07,tlu Add a wrapper for client auth FSM
|
||||
01b,21jun07,tlu Fix so a session remains in open state when rx user request
|
||||
01a,27apr07,tlu Created.
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_cstyle.h>
|
||||
#include <ipcom_sock.h>
|
||||
#include <ipcom_os.h>
|
||||
#include <ipcom_syslog.h>
|
||||
#include <ipcom_err.h>
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_ipd.h>
|
||||
|
||||
#include <ipnet_h.h>
|
||||
|
||||
#include "ipdiameter.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IP_EXTERN Ipdiameter_data ipdiameter;
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/* This is a compile flag, turning on it will build debug message into image */
|
||||
#undef DIAMETER_DEBUG
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* LOCAL PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IP_STATIC Ip_err
|
||||
ipdiameter_client_auth_stateful_fsm(Ipdiameter_session *session,
|
||||
struct Ipdiameter_header *hdr, int event);
|
||||
IP_STATIC Ip_err
|
||||
ipdiameter_client_auth_stateless_fsm(Ipdiameter_session *session,
|
||||
struct Ipdiameter_header *hdr, int event);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* DATA
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_client_auth_fsm
|
||||
*===========================================================================
|
||||
* Description: wrapper function for client auth FSM to deal with both stateful
|
||||
* stateful and stateless FSMs
|
||||
* Parameters:
|
||||
* Returns: result
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameter_client_auth_fsm(Ipdiameter_session *session,
|
||||
struct Ipdiameter_header *hdr, int event)
|
||||
{
|
||||
if (session->is_stateful)
|
||||
return ipdiameter_client_auth_stateful_fsm(session, hdr, event);
|
||||
else
|
||||
return ipdiameter_client_auth_stateless_fsm(session, hdr, event);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_client_auth_stateful_fsm
|
||||
*===========================================================================
|
||||
* Description: client session stateful FSM
|
||||
* refer to RFC 3588, section 8.1
|
||||
* Parameters:
|
||||
* Returns: result
|
||||
*
|
||||
*/
|
||||
IP_STATIC Ip_err
|
||||
ipdiameter_client_auth_stateful_fsm(Ipdiameter_session *session,
|
||||
struct Ipdiameter_header *hdr, int event)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
char session_id[IPDIAMETER_MAX_SESSION_ID_SIZE] = IPDIAMETER_NULL_STRING;
|
||||
Ipdiameter_header *hdr_v = (Ipdiameter_header *)hdr;
|
||||
|
||||
|
||||
/* find the associated session */
|
||||
if (session == IP_NULL && hdr != IP_NULL)
|
||||
{
|
||||
retval = ipdiameter_avp_get_session_id(hdr_v, session_id);
|
||||
if (retval == IPCOM_SUCCESS)
|
||||
{
|
||||
/* Search through the session's request list */
|
||||
session = ipdiameter_find_session(session_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (session == IP_NULL) {
|
||||
IPCOM_LOG0(ERR, "ipdiameter_client_auth_stateful_fsm, failed to get a session\n");
|
||||
return IPCOM_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("Calling ipdiameter_client_auth_stateful_fsm, state %d, event %d\n",
|
||||
session->state, event);
|
||||
#endif
|
||||
|
||||
switch (session->state)
|
||||
{
|
||||
case DIAMETER_SESSION_STATE_IDLE:
|
||||
switch (event) {
|
||||
case DIAMETER_CLIENT_AUTH_EV_ACCESS_REQ:
|
||||
retval = ipdiameter_session_pkt_send(session, hdr_v);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the access req packet\n");
|
||||
else
|
||||
{
|
||||
IPCOM_LOG0(INFO, "ipdiameter_client_auth_stateful_fsm, send outthe access req packet\n");
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_PENDING);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ASR_RX:
|
||||
/* sent out ASA */
|
||||
retval = ipdiameter_send_ASA(session, IP_INVALID_SOCKET,
|
||||
IP_NULL, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the ASA packet\n");
|
||||
}
|
||||
|
||||
/* session remains in Idle state */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_SESSION_STATE_PENDING:
|
||||
switch (event) {
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX_DEFAULT:
|
||||
/* User notification of access accept packet has already been sent out. */
|
||||
|
||||
/* Check to start session timers */
|
||||
ipdiameter_session_start_timers(session, hdr);
|
||||
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_OPEN);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX_NO_SERVICE:
|
||||
/* sent out STR */
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_ADMINISTRATIVE);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the STR packet\n");
|
||||
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_DISCON);
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX_PROC_ERR:
|
||||
/* sent out STR */
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_BAD_ANSWER);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the STR packet\n");
|
||||
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_DISCON);
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX_REJECT:
|
||||
/* User notification of access reject packet has already been sent out. */
|
||||
|
||||
/* State goes back to Idle */
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_IDLE);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_SESSION_STATE_OPEN:
|
||||
switch (event) {
|
||||
case DIAMETER_CLIENT_AUTH_EV_ACCESS_REQ_SERVICE:
|
||||
retval = ipdiameter_session_pkt_send(session, hdr_v);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out req packet\n");
|
||||
|
||||
/* session remains in open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX:
|
||||
/* User notification of access accept packet has already been sent out. */
|
||||
|
||||
/* Check to start session timers */
|
||||
ipdiameter_session_start_timers(session, hdr);
|
||||
|
||||
/* No action to change session's state ... remains open */
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX_REJECT:
|
||||
/* User notification of access reject packet has already been sent out. */
|
||||
|
||||
/* Disconnect user/device */
|
||||
retval = ipdiameter_discon_user(session);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_RAR_RX:
|
||||
if (session->perform_re_auth)
|
||||
{
|
||||
/* sent out RAA with reult-code = SUCCESS */
|
||||
retval = ipdiameter_send_RAA(session, IP_INVALID_SOCKET,
|
||||
IP_NULL, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the RAA packet\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* sent out RAA with reult-code != SUCCESS */
|
||||
retval = ipdiameter_send_RAA(session, IP_INVALID_SOCKET,
|
||||
IP_NULL, hdr_v, DIAMETER_UNABLE_TO_COMPLY);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send RAA packet\n");
|
||||
|
||||
/* Disconnect user/device */
|
||||
retval = ipdiameter_discon_user(session);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_TIMEOUT_EXPIRES:
|
||||
/* sent out STR */
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_SESSION_TIMEOUT);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the STR packet\n");
|
||||
}
|
||||
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_DISCON);
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ASR_RX:
|
||||
if (ipdiameter.ASR_comply)
|
||||
{
|
||||
/* sent out ASA with reult-code = SUCCESS */
|
||||
retval = ipdiameter_send_ASA(session, IP_INVALID_SOCKET,
|
||||
IP_NULL, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send ASR packet\n");
|
||||
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_ADMINISTRATIVE);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send STR packet\n");
|
||||
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_DISCON);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* sent out ASA with reult-code != SUCCESS */
|
||||
retval = ipdiameter_send_ASA(session, IP_INVALID_SOCKET,
|
||||
IP_NULL, hdr_v, DIAMETER_UNABLE_TO_COMPLY);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send ASR packet\n");
|
||||
|
||||
/* the session remains open state */
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_LIFETIME_GRACE_EXPIRES:
|
||||
/* sent out STR */
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_AUTH_EXPIRED);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the STR packet\n");
|
||||
}
|
||||
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_DISCON);
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_SERV_TERMINATED:
|
||||
/* sent out STR */
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_LOGOUT);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the STR packet\n");
|
||||
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_DISCON);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_SESSION_STATE_DISCON:
|
||||
switch (event) {
|
||||
case DIAMETER_CLIENT_AUTH_EV_ASR_RX:
|
||||
/* sent out ASA with reult-code = SUCCESS */
|
||||
retval = ipdiameter_send_ASA(session, IP_INVALID_SOCKET,
|
||||
IP_NULL, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, failed to send out the ASR packet\n");
|
||||
}
|
||||
|
||||
/* Disconnect user/device */
|
||||
retval = ipdiameter_discon_user(session);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_STA_RX:
|
||||
/* Disconnect user/device */
|
||||
retval = ipdiameter_discon_user(session);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipdiameter_print_session(session);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_client_auth_stateless_fsm
|
||||
*===========================================================================
|
||||
* Description: client session stateless FSM
|
||||
* refer to RFC 3588, section 8.1
|
||||
* Parameters:
|
||||
* Returns: result
|
||||
*
|
||||
*/
|
||||
|
||||
IP_STATIC Ip_err
|
||||
ipdiameter_client_auth_stateless_fsm(Ipdiameter_session *session,
|
||||
struct Ipdiameter_header *hdr, int event)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
char session_id[IPDIAMETER_MAX_SESSION_ID_SIZE] = IPDIAMETER_NULL_STRING;
|
||||
Ip_size_t data_length;
|
||||
Ip_u8 *data;
|
||||
Ipdiameter_header *hdr_v = (Ipdiameter_header *)hdr;
|
||||
|
||||
|
||||
/* find the associated session */
|
||||
if (session == IP_NULL && hdr != IP_NULL)
|
||||
{
|
||||
retval = ipdiameter_get_avp(hdr_v, DIAMETER_AVP_CODE_Session_Id,(Ip_u32 *) &data_length, &data);
|
||||
if (retval == IPCOM_SUCCESS) {
|
||||
if (data_length >= IPDIAMETER_MAX_SESSION_ID_SIZE) {
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateful_fsm, session ID exceeds the max length\n");
|
||||
return IPCOM_ERR_REACHED_MAX;
|
||||
}
|
||||
|
||||
ipcom_memcpy(session_id, data, data_length);
|
||||
session_id[data_length] = '\0';
|
||||
session = ipdiameter_find_session(session_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (session == IP_NULL) {
|
||||
IPCOM_LOG0(ERR, "ipdiameter_client_auth_stateless_fsm, failed to get a session\n");
|
||||
return IPCOM_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("Calling ipdiameter_client_auth_stateless_fsm, state %d, event %d\n",
|
||||
session->state, event);
|
||||
#endif
|
||||
|
||||
switch (session->state)
|
||||
{
|
||||
case DIAMETER_SESSION_STATE_IDLE:
|
||||
switch (event) {
|
||||
case DIAMETER_CLIENT_AUTH_EV_ACCESS_REQ:
|
||||
retval = ipdiameter_session_pkt_send(session, hdr_v);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateless_fsm, failed to send out the access req packet\n");
|
||||
else
|
||||
/* change the session state to pending */
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_PENDING);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_SESSION_STATE_PENDING:
|
||||
switch (event) {
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX_NO_STATE:
|
||||
/* User notification of access accept packet has already
|
||||
* been sent out. */
|
||||
ipdiameter_session_set_state(session, DIAMETER_SESSION_STATE_OPEN);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_ANSWER_RX_REJECT:
|
||||
/* Cleanup */
|
||||
retval = ipdiameter_session_cleanup(session);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_SESSION_STATE_OPEN:
|
||||
switch (event) {
|
||||
case DIAMETER_CLIENT_AUTH_EV_ACCESS_REQ_SERVICE:
|
||||
retval = ipdiameter_session_pkt_send(session, hdr_v);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateless_fsm, failed to send out req packet\n");
|
||||
|
||||
/* session remains in open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_TIMEOUT_EXPIRES:
|
||||
/* sent out STR */
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_SESSION_TIMEOUT);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_client_auth_stateless_fsm, failed to send out the STR packet\n");
|
||||
|
||||
/* Disconnect user/device */
|
||||
retval = ipdiameter_discon_user(session);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_CLIENT_AUTH_EV_SERV_TERMINATED:
|
||||
/* sent out STR */
|
||||
retval = ipdiameter_send_STR(session, DIAMETER_LOGOUT);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING,"ipdiameter_client_auth_stateless_fsm, failed to send out the STR packet\n");
|
||||
|
||||
/* Disconnect user/device */
|
||||
retval = ipdiameter_discon_user(session);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipdiameter_print_session(session);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,233 @@
|
||||
/* ipdiameter_pagent.c - Diameter proxy agent file */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement. No license to Wind River intellectual property rights
|
||||
* is granted herein. All rights not licensed by Wind River are reserved
|
||||
* by Wind River.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01e,31jan08,tlu Remove Open Diameter test macro definition
|
||||
01d,12nov07,tlu Add open() function for proxy agent
|
||||
01c,12nov07,tlu Cleaned up
|
||||
01b,09nov07,ggz Included ipdiameter_pagent.h file
|
||||
01a,05jul07,cwu Created.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This library provides routines for user authentication access request.
|
||||
|
||||
To use this feature, include the following component: INCLUDE_IPDIAMETERP
|
||||
|
||||
INCLUDE FILES: ipdiameter.h, ipdiameter_pagent.h, ipdiameter_config.h
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* DESCRIPTION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* CONFIGURATION
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#include "ipdiameter_config.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
|
||||
/* ipcom */
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_cstyle.h>
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_os.h>
|
||||
#include <ipcom_err.h>
|
||||
#include <ipcom_sysvar.h>
|
||||
#include <ipcom_syslog.h>
|
||||
|
||||
|
||||
/* ipdiameter */
|
||||
#include "ipdiameter.h"
|
||||
#include "ipdiameter_pagent.h"
|
||||
|
||||
|
||||
/*
|
||||
**************************************************************************
|
||||
* DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define IPDIAMETERP_PROC "ipdiameterpd"
|
||||
|
||||
|
||||
/* This is a compile flag, turning on it will build debug message into image */
|
||||
#undef DIAMETER_DEBUG
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IP_EXTERN Ipdiameter_data ipdiameter;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterp_create
|
||||
*===========================================================================
|
||||
* Description: Initialize global IPDIAMETER data 'ipdiameter'.
|
||||
* Parameters: .
|
||||
* Returns: .
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterp_create(void)
|
||||
{
|
||||
Ip_err ret_val = IPCOM_SUCCESS;
|
||||
|
||||
ret_val = ipdiameter_common_create(DIAMETER_PEER_PROXY_AGENT);
|
||||
|
||||
/* Initialize close and exit functions */
|
||||
ipdiameter.close = ipdiameterp_close;
|
||||
ipdiameter.exit = ipdiameterp_exit;
|
||||
ipdiameter.open = ipdiameterp_open;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterp_close
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterp_close(void)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
|
||||
retval = ipdiameter_common_close();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterp_exit
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterp_exit(void)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
|
||||
retval = ipdiameter_common_exit();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterp_open
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterp_open(void)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterp_start
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterp_start(void)
|
||||
{
|
||||
Ip_err ret = IPCOM_SUCCESS;
|
||||
|
||||
ret = ipdiameter_common_start(IPDIAMETERP_PROC);
|
||||
if (ret != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameterp_start: Failed on ipdiameter_common_start");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameterp_stop
|
||||
*===========================================================================
|
||||
* Description:
|
||||
* Parameters:
|
||||
* Returns:
|
||||
*
|
||||
*/
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameterp_stop(void)
|
||||
{
|
||||
Ip_err ret = IPCOM_SUCCESS;
|
||||
|
||||
ret = ipdiameter_common_stop();
|
||||
if (ret != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameterp_stop: Failed on ipdiameter_common_stop");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,885 @@
|
||||
/* ipdiameter_peer_fsm.c - IPNet Diameter peer FSM file */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement. No license to Wind River intellectual property rights
|
||||
* is granted herein. All rights not licensed by Wind River are reserved
|
||||
* by Wind River.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01e,03feb09,tlu Remove R_RCV_CEA and I_RCV_CER events from peer FSM
|
||||
01d,05apr08,ggz Modifications for non blocking TCP connection with peers
|
||||
01c,05sep07,tlu Fix checking of the return code from processing CER
|
||||
01b,05jul07,tlu Replace ipcom_printf by IPCOM_LOG
|
||||
01a,03may07,tlu Created.
|
||||
*/
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_cstyle.h>
|
||||
#include <ipcom_sock.h>
|
||||
#include <ipcom_os.h>
|
||||
#include <ipcom_syslog.h>
|
||||
#include <ipcom_err.h>
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_ipd.h>
|
||||
|
||||
#include <ipnet_h.h>
|
||||
|
||||
#include "ipdiameter.h"
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IP_EXTERN Ipdiameter_data ipdiameter;
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/* This is a compile flag, turning on it will build debug message into image */
|
||||
#undef DIAMETER_DEBUG
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* LOCAL PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* DATA
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
* Refer to RFC 3588, section 5.6
|
||||
*/
|
||||
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameter_peer_fsm(Ipdiameter_peer_entry *peer, struct Ipdiameter_header *hdr, int event)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
Ipdiameter_header *hdr_v = (Ipdiameter_header *)hdr;
|
||||
Ip_bool win_elect;
|
||||
Ip_u32 result_code = DIAMETER_SUCCESS;
|
||||
Ip_fd fd = IP_INVALID_SOCKET, fd6 = IP_INVALID_SOCKET;
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("Calling ipdiameter_peer_fsm, state %s, event %d\n",
|
||||
ipdiameter_peer_state(peer->state), event);
|
||||
#endif
|
||||
if (peer == IP_NULL) {
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, pass in a NULL peer\n");
|
||||
return IPCOM_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
switch (peer->state)
|
||||
{
|
||||
case DIAMETER_PEER_STATE_CLOSED:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_START:
|
||||
|
||||
if (ipdiameter.node_type == DIAMETER_PEER_PROXY_AGENT)
|
||||
{
|
||||
/* initiate non-blocking connection */
|
||||
retval = ipdiameter_peer_init_conn_req(peer);
|
||||
|
||||
/* Warning: this state of peer is used in non blocking select processing */
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK);
|
||||
|
||||
/* The socket is in non blocing mode but the connection might
|
||||
have already been established. If yes then continue procesiing here.
|
||||
Otherwise the connection will be processed in select function after
|
||||
the socket reply */
|
||||
if ((retval != IPCOM_SUCCESS) && (retval != IP_ERRNO_EINPROGRESS))
|
||||
{
|
||||
ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_NACK);
|
||||
retval = IPCOM_ERR_FAILED;
|
||||
}
|
||||
else if (retval == IP_ERRNO_EINPROGRESS)
|
||||
{
|
||||
/* IP_ERRNO_EINPROGRESS - leave the peers state in
|
||||
DIAMETER_PEER_STATE_WAIT_CONN_ACK. The connection will be handled
|
||||
when the socket replyes */
|
||||
retval = IPCOM_SUCCESS;
|
||||
}
|
||||
else /* Success */
|
||||
{
|
||||
/* Immidiate socket connection has been established. Run the peer FSM */
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_ACK);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* initiate connect request */
|
||||
retval = ipdiameter_peer_init_conn_req(peer);
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK);
|
||||
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the packet\n");
|
||||
ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_NACK);
|
||||
retval = IPCOM_ERR_FAILED;
|
||||
} else {
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_I_RCV_CONN_ACK);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_CONN_CER:
|
||||
case DIAMETER_PEER_EV_R_RCV_CER:
|
||||
#ifdef IPCOM_USE_INET
|
||||
fd = peer->fd;
|
||||
#endif
|
||||
#ifdef IPCOM_USE_INET6
|
||||
fd6 = peer->fd6;
|
||||
#endif
|
||||
|
||||
if (fd == IP_INVALID_SOCKET && fd6 == IP_INVALID_SOCKET)
|
||||
/* peer is not connected, remains in CLOSED state */
|
||||
break;
|
||||
|
||||
if (!peer->initiator)
|
||||
{
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_peer_fsm: respond to accept the connect\n");
|
||||
#endif
|
||||
/* respond to accept the connection */
|
||||
retval = ipdiameter_peer_resp_accept(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to accept the connect\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* process the CER */
|
||||
result_code = ipdiameter_peer_process_CER(peer, hdr);
|
||||
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* cancel the recon timer */
|
||||
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
||||
|
||||
/* respond to send the CEA */
|
||||
retval = ipdiameter_send_CEA(peer, hdr_v, result_code);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
||||
|
||||
/* check whether there is pending package to transmit */
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_STATE_WAIT_CONN_ACK:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_I_RCV_CONN_ACK:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* send the CER */
|
||||
retval = ipdiameter_send_CER(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_I_CEA);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_CONN_NACK:
|
||||
/* clean up */
|
||||
retval = ipdiameter_peer_cleanup(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer cleanup\n");
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_CONN_CER:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* respond to accept the connection */
|
||||
retval = ipdiameter_peer_resp_accept(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to accept the connect\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* process the CER */
|
||||
retval = ipdiameter_peer_process_CER(peer, hdr);
|
||||
if (retval != DIAMETER_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to process the CER\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK_ELECT);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_TIMEOUT:
|
||||
/* process the error */
|
||||
retval = ipdiameter_peer_error(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_STATE_WAIT_I_CEA:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_I_RCV_CEA:
|
||||
/* process the CEA */
|
||||
retval = ipdiameter_peer_process_CEA(peer, hdr);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to process the CEA\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_I_OPEN);
|
||||
|
||||
/* check whether there is pending package to transmit */
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_CONN_CER:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* respond to accept the connection */
|
||||
retval = ipdiameter_peer_resp_accept(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to accept the connect\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* process the CER */
|
||||
retval = ipdiameter_peer_process_CER(peer, hdr);
|
||||
if (retval != DIAMETER_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to process the CER\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* perform the peer election */
|
||||
win_elect = ipdiameter_peer_elect(peer);
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_RETURNS);
|
||||
|
||||
if (win_elect)
|
||||
{
|
||||
retval = ipdiameter_peer_fsm(peer, hdr, DIAMETER_PEER_EV_WIN_ELECTION);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed in peer FSM with EV_WIN_ELECTION\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_PEER_DISC:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_NON_CEA:
|
||||
/* process the error */
|
||||
retval = ipdiameter_peer_error(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_TIMEOUT:
|
||||
/* process the error */
|
||||
retval = ipdiameter_peer_error(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_STATE_WAIT_CONN_ACK_ELECT:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_I_RCV_CONN_ACK:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* send the CER */
|
||||
retval = ipdiameter_send_CER(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* perform the peer election */
|
||||
win_elect = ipdiameter_peer_elect(peer);
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_RETURNS);
|
||||
|
||||
if (win_elect)
|
||||
{
|
||||
retval = ipdiameter_peer_fsm(peer, hdr, DIAMETER_PEER_EV_WIN_ELECTION);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed in peer FSM with EV_WIN_ELECTION\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_CONN_NACK:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* cancel the recon timer */
|
||||
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
||||
|
||||
/* send the CEA */
|
||||
retval = ipdiameter_send_CEA(peer, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Change the state to open */
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
||||
|
||||
/* check whether there is pending package to transmit */
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_PEER_DISC:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_CONN_CER:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Reject the peer */
|
||||
retval = ipdiameter_peer_reject(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_CONN_ACK_ELECT);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_TIMEOUT:
|
||||
/* process the error */
|
||||
retval = ipdiameter_peer_error(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_STATE_WAIT_RETURNS:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_WIN_ELECTION:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer if the local host is the winner */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* cancel the recon timer */
|
||||
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
||||
|
||||
/* Send the CEA */
|
||||
retval = ipdiameter_send_CEA(peer, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
||||
|
||||
/* check whether there is pending package to transmit */
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_PEER_DISC:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* cancel the recon timer */
|
||||
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
||||
|
||||
/* Send the CEA */
|
||||
retval = ipdiameter_send_CEA(peer, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_R_OPEN);
|
||||
|
||||
/* check whether there is pending package to transmit */
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_CEA:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* cancel the recon timer */
|
||||
(void)ipcom_tmo2_cancel(&peer->reconn_tmo);
|
||||
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_I_OPEN);
|
||||
|
||||
/* check whether there is pending package to transmit */
|
||||
retval = ipdiameter_peer_fsm(peer, IP_NULL, DIAMETER_PEER_EV_SEND_MESSAGE);
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_PEER_DISC:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_I_CEA);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_CONN_CER:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Reject the peer */
|
||||
retval = ipdiameter_peer_reject(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_WAIT_RETURNS);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_TIMEOUT:
|
||||
/* process the error */
|
||||
retval = ipdiameter_peer_error(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_STATE_R_OPEN:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_SEND_MESSAGE:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* send out the messge */
|
||||
retval = ipdiameter_peer_send_msg(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm: failed to send out the message\n");
|
||||
}
|
||||
|
||||
/* the peer remains R-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_RCV_MESSAGE:
|
||||
/* process the messge */
|
||||
retval = ipdiameter_peer_process_msg(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm: failed to process the message\n");
|
||||
|
||||
/* the peer remains R-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_RCV_DWR:
|
||||
/* process the DWR messge */
|
||||
result_code = ipdiameter_peer_process_DWR(peer, hdr);
|
||||
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* send out the DWA messge */
|
||||
retval = ipdiameter_send_DWA(peer, hdr_v, result_code);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to send out the DWA message\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* the peer remains R-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_RCV_DWA:
|
||||
/* process the DWA messge */
|
||||
retval = ipdiameter_peer_process_DWA(peer, hdr);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to process the DWA\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* the peer remains R-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_CONN_CER:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Reject the peer */
|
||||
retval = ipdiameter_peer_reject(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
||||
}
|
||||
|
||||
/* the peer remains R-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_STOP:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* start reconn timer */
|
||||
retval = ipdiameter_peer_start_reconn_timer(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to start reconn timer\n");
|
||||
|
||||
/* send out the DPR */
|
||||
retval = ipdiameter_send_DPR(peer, DIAMETER_PEER_DO_NOT_WANT_TO_TALK_TO_YOU);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPR message\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSING);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_RCV_DPR:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* send out the DPA */
|
||||
retval = ipdiameter_send_DPA(peer, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPA message\n");
|
||||
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_PEER_DISC:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_STATE_I_OPEN:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_SEND_MESSAGE:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* send out the messge */
|
||||
retval = ipdiameter_peer_send_msg(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm, failed to send out the CEA packet\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* the session remains I-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_MESSAGE:
|
||||
/* process the messge */
|
||||
retval = ipdiameter_peer_process_msg(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm: failed to process the message\n");
|
||||
|
||||
/* the session remains I-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_DWR:
|
||||
/* process the DWR messge */
|
||||
result_code = ipdiameter_peer_process_DWR(peer, hdr);
|
||||
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* send out the DWA messge */
|
||||
retval = ipdiameter_send_DWA(peer, hdr_v, result_code);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to send out the DWA message\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* the session remains I-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_DWA:
|
||||
/* process the DWA messge */
|
||||
retval = ipdiameter_peer_process_DWA(peer, hdr);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed to process the DWA\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* the session remains I-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_CONN_CER:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Reject the peer */
|
||||
retval = ipdiameter_peer_reject(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to reject the peer\n");
|
||||
}
|
||||
|
||||
/* the session remains I-Open state */
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_STOP:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* start reconn timer */
|
||||
retval = ipdiameter_peer_start_reconn_timer(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to start reconn timer\n");
|
||||
|
||||
/* send out the DPR */
|
||||
retval = ipdiameter_send_DPR(peer, DIAMETER_PEER_DO_NOT_WANT_TO_TALK_TO_YOU);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPR message\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSING);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_RCV_DPR:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* send out the DPA */
|
||||
retval = ipdiameter_send_DPA(peer, hdr_v, DIAMETER_SUCCESS);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to send out the DPA message\n");
|
||||
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_PEER_DISC:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_STATE_CLOSING:
|
||||
switch (event) {
|
||||
case DIAMETER_PEER_EV_I_RCV_DPA:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_RCV_DPA:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_TIMEOUT:
|
||||
/* process the error */
|
||||
retval = ipdiameter_peer_error(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(ERR, "ipdiameter_peer_fsm: failed in peer error handling\n");
|
||||
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_I_PEER_DISC:
|
||||
if (peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
case DIAMETER_PEER_EV_R_PEER_DISC:
|
||||
if (!peer->initiator)
|
||||
{
|
||||
/* Disconnect the peer */
|
||||
retval = ipdiameter_peer_disc(peer);
|
||||
if (retval != IPCOM_SUCCESS)
|
||||
IPCOM_LOG0(WARNING, "ipdiameter_peer_fsm, failed to disconnect the peer\n");
|
||||
}
|
||||
|
||||
ipdiameter_peer_set_state(peer, DIAMETER_PEER_STATE_CLOSED);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_peer_fsm successful\n");
|
||||
ipdiameter_print_peer(peer);
|
||||
#endif
|
||||
return retval;
|
||||
|
||||
error:
|
||||
(void)ipdiameter_peer_disc(peer);
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_peer_fsm failed\n");
|
||||
ipdiameter_print_peer(peer);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,707 @@
|
||||
/* ipdiameter_tls.c - IPNet Diameter TLS support file */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007, 2023 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute or otherwise make use of this software
|
||||
* may be licensed only pursuant to the terms of an applicable Wind River
|
||||
* license agreement. No license to Wind River intellectual property rights
|
||||
* is granted herein. All rights not licensed by Wind River are reserved
|
||||
* by Wind River.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01i,17oct23,rjq Fix Y2038 issue.
|
||||
01h,16jul10,hfc secureKeyDB support for diameter
|
||||
01g,10mar09,tlu Fix Linux build warning
|
||||
01f,11feb09,tlu Remove seeding PRNG from Diameter TLS init (PRNG is already
|
||||
seeded by ipcrypto init)
|
||||
01e,19oct07,tlu Fix IPV6 only build error
|
||||
01d,10oct07,tlu Port to Linux
|
||||
01c,21sep07,tlu Modify the return code from verifying certificate routine
|
||||
and add debug code to set target time to be within valid
|
||||
certificate period
|
||||
01b,05sep07,tlu Replace strlcpy by ipcom_strlcpy
|
||||
01a,09aug07,tlu Created.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This library provides support routines for Diameter TLS.
|
||||
|
||||
|
||||
INCLUDE FILES: ipdiameter.h, ipdiameter_tls.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* INCLUDE FILES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#define IPCOM_USE_CLIB_PROTO
|
||||
#include <ipcom_type.h>
|
||||
#include <ipcom_os.h>
|
||||
#include <ipcom_clib.h>
|
||||
#include <ipcom_syslog.h>
|
||||
#include <ipcom_err.h>
|
||||
#include <ipcom_time.h>
|
||||
|
||||
#include <ipcom_file.h>
|
||||
|
||||
#include "ipdiameter.h"
|
||||
#include "ipdiameter_tls.h"
|
||||
|
||||
|
||||
#if defined(IPCOM_USE_KEY_DB) && defined(_WRS_CONFIG_IPDIAMETER_SEC_KEY_DB)
|
||||
#include "ipcom_key_db.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* EXTERN PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IP_EXTERN Ipdiameter_data ipdiameter;
|
||||
|
||||
|
||||
#ifdef IPSSL
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* DEFINES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/* This is a compile flag, turning on it will build debug message into image */
|
||||
#undef DIAMETER_DEBUG
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* LOCAL PROTOTYPES
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
IP_STATIC int ipdiameter_verify_callback(int statusIn,
|
||||
X509_STORE_CTX * pCertStore);
|
||||
#endif
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameter_setup_ssl_ctx();
|
||||
|
||||
#ifndef _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB
|
||||
|
||||
IP_STATIC int ipdiameter_passwd_cb
|
||||
(
|
||||
char * pPassword, /* private key password */
|
||||
int passwordSize, /* private key length */
|
||||
int flags, /* unused */
|
||||
void * pUserdata /* user supplied key password */
|
||||
);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* PRIVATE FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
IP_STATIC int ipdiameter_passwd_cb
|
||||
(
|
||||
char * pPassword, /* private key password */
|
||||
int passwordSize, /* private key length */
|
||||
int flags, /* unused */
|
||||
void * pUserdata /* unused */
|
||||
)
|
||||
{
|
||||
|
||||
/* Check password buffer length */
|
||||
if(passwordSize < IPDIAMETER_MAX_PASSWORD_SIZE)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_passwd_cb: TLS password check error - too short\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
if(pUserdata != IP_NULL)
|
||||
{
|
||||
/* Get the password */
|
||||
ipcom_strlcpy(pPassword, pUserdata, passwordSize);
|
||||
|
||||
/* debug */
|
||||
IPCOM_LOG1(DEBUG, "ipdiameter_passwd_cb: TLS password %s\n", pPassword);
|
||||
|
||||
return (int)(ipcom_strlen(pPassword));
|
||||
}
|
||||
else
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_passwd_cb: TLS password check error - bad binding\n");
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB */
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_verify_callback
|
||||
*===========================================================================
|
||||
* Description: Performs certifcate verfication. This routine is called
|
||||
* by the SSL layer when certificate verification is performed.
|
||||
* Parameters:
|
||||
* RETURNS: Passed in status
|
||||
*
|
||||
*/
|
||||
#ifdef DIAMETER_DEBUG
|
||||
IP_STATIC int ipdiameter_verify_callback
|
||||
(
|
||||
int statusIn, /* certificate status */
|
||||
X509_STORE_CTX * pCertStore /* certificate store */
|
||||
)
|
||||
{
|
||||
/* Display certificate information for debug */
|
||||
X509 * pCert = X509_STORE_CTX_get_current_cert(pCertStore);
|
||||
int err = X509_STORE_CTX_get_error(pCertStore);
|
||||
char data[256];
|
||||
|
||||
IPCOM_LOG0(DEBUG, "Calling ipdiameter_verify_callback\n");
|
||||
|
||||
/* Display the contents to the shell */
|
||||
IPCOM_LOG7(DEBUG, "\nCertificate verification status\n" \
|
||||
"statusIn :%ld\n" \
|
||||
"certStore :0x%08X\n" \
|
||||
"cert :0x%08X\n" \
|
||||
"depth :%ld\n" \
|
||||
"issuer :%s\n" \
|
||||
"subject :%s\n" \
|
||||
"err[%d] :%s\n",
|
||||
statusIn,
|
||||
pCertStore,
|
||||
pCert,
|
||||
X509_STORE_CTX_get_error_depth(pCertStore),
|
||||
(char*)X509_NAME_oneline(X509_get_issuer_name(pCert),
|
||||
data, sizeof(data)),
|
||||
(char*)X509_NAME_oneline(X509_get_subject_name(pCert),
|
||||
data, sizeof(data)),
|
||||
(char*)X509_verify_cert_error_string(err));
|
||||
|
||||
/* Return status */
|
||||
return(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* PUBLIC FUNCTIONS
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_setup_ssl_ctx
|
||||
*===========================================================================
|
||||
* Description: Initialize local node's ssl_ctx context.
|
||||
* Parameters: AVP length: only last 3 octets value is valid
|
||||
* length is in host format
|
||||
*
|
||||
*/
|
||||
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameter_setup_ssl_ctx(void)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
#if defined(IPCOM_USE_KEY_DB) && defined(_WRS_CONFIG_IPDIAMETER_SEC_KEY_DB)
|
||||
EVP_PKEY* private_key = IP_NULL;
|
||||
#endif
|
||||
static Ip_bool ipdiameter_sslInit = IP_FALSE;
|
||||
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("Calling ipdiameter_setup_ssl_ctx\n");
|
||||
#endif
|
||||
|
||||
/* Start up and init the SSL library */
|
||||
if(!ipdiameter_sslInit)
|
||||
{
|
||||
SSL_library_init(); /* Always returns 1 */
|
||||
ERR_load_crypto_strings();
|
||||
SSL_load_error_strings();
|
||||
/* PRNG is seeded by ipcrypto init code, no need to seed PRNG anymore
|
||||
RAND_seed(ipdiameter_rnd_seed, sizeof ipdiameter_rnd_seed); */
|
||||
ipdiameter_sslInit = IP_TRUE;
|
||||
}
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
{
|
||||
struct Ip_tm timeStruct, *tmp;
|
||||
struct Ip_timeval tv;
|
||||
char buf[26];
|
||||
|
||||
timeStruct.tm_sec = 0;
|
||||
timeStruct.tm_min = 0;
|
||||
timeStruct.tm_hour = 0;
|
||||
timeStruct.tm_mday = 1;
|
||||
timeStruct.tm_mon = 9;
|
||||
timeStruct.tm_year = 2007 - 1900; /* Year - 1900 */
|
||||
timeStruct.tm_wday = 0;
|
||||
|
||||
/* Create the unix time */
|
||||
tv.tv_sec = ipcom_mktime(&timeStruct);
|
||||
tv.tv_usec = 0;
|
||||
|
||||
/* print datestring. */
|
||||
ipcom_printf("%s\n", ipcom_asctime_r(&timeStruct, buf));
|
||||
|
||||
/* Set the date */
|
||||
if (ipcom_settimeofday(&tv, IP_NULL) != 0)
|
||||
{
|
||||
ipcom_printf("date: failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void)ipcom_gettimeofday(&tv, IP_NULL);
|
||||
tmp = ipcom_localtime((Ip_time_t *)&tv.tv_sec);
|
||||
if (tmp == IP_NULL)
|
||||
{
|
||||
ipcom_printf("date: failed\n");
|
||||
return 0;
|
||||
}
|
||||
/* print datestring. */
|
||||
ipcom_printf("%s\n", ipcom_asctime_r(tmp, buf));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
IPDIAMETER_LOCK();
|
||||
|
||||
/* Create a new SSL_CTX context */
|
||||
ipdiameter.ssl_ctx = SSL_CTX_new(TLSv1_method());
|
||||
if(!ipdiameter.ssl_ctx)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_setup_ssl_ctx: SSL_CTX_new() failed\n");
|
||||
IPDIAMETER_LEAVE(IPCOM_ERR_FAILED);
|
||||
}
|
||||
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_setup_ssl_ctx: created ssl_ctx\n");
|
||||
#ifdef DIAMETER_DEBUG
|
||||
{
|
||||
IP_FILE *file;
|
||||
|
||||
file = ipcom_fopen(ipdiameter.cacertfile, "r");
|
||||
if(file == IP_NULL)
|
||||
{
|
||||
ipcom_printf("fopen %d failed\n", ipdiameter.cacertfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipcom_printf("fopen %s succeeded\n", ipdiameter.cacertfile);
|
||||
ipcom_fclose(file);
|
||||
}
|
||||
|
||||
file = ipcom_fopen(ipdiameter.certfile, "r");
|
||||
if(file == IP_NULL)
|
||||
{
|
||||
ipcom_printf("fopen %s failed\n", ipdiameter.certfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipcom_printf("fopen %s succeeded\n", ipdiameter.certfile);
|
||||
ipcom_fclose(file);
|
||||
}
|
||||
|
||||
#ifndef _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB
|
||||
|
||||
file = ipcom_fopen(ipdiameter.keyfile, "r");
|
||||
if(file == IP_NULL)
|
||||
{
|
||||
ipcom_printf("fopen %d failed\n", ipdiameter.keyfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipcom_printf("fopen %s succeeded\n", ipdiameter.keyfile);
|
||||
ipcom_fclose(file);
|
||||
}
|
||||
#endif /* _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB */
|
||||
}
|
||||
#endif /* DIAMETER_DEBUG */
|
||||
|
||||
|
||||
/* load CA root certificate */
|
||||
if (SSL_CTX_load_verify_locations(ipdiameter.ssl_ctx,
|
||||
ipdiameter.cacertfile, ipdiameter.rootdir) != 1)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_setup_ssl_ctx: failed to load CA root cert file\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_setup_ssl_ctx: loaded CA root certificate\n");
|
||||
|
||||
/* load local node certificate file */
|
||||
if (SSL_CTX_use_certificate_file(ipdiameter.ssl_ctx,
|
||||
ipdiameter.certfile, SSL_FILETYPE_PEM) != 1)
|
||||
{
|
||||
IPCOM_LOG1(ERR, "ipdiameter_setup_ssl_ctx: failed to load node cert file%s\n",
|
||||
ipdiameter.certfile);
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_setup_ssl_ctx: loaded node certificate\n");
|
||||
|
||||
#if defined(IPCOM_USE_KEY_DB) && defined(_WRS_CONFIG_IPDIAMETER_SEC_KEY_DB)
|
||||
|
||||
if((private_key=ipcom_key_db_pkey_get(ipdiameter.keyfile))==IP_NULL)
|
||||
{
|
||||
IPCOM_LOG1(ERR,"ipdiameter_setup_ssl_ctx : failed to retrieve TLS "
|
||||
"private key file from secure key db using key id %s \n",ipdiameter.keyfile);
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
#ifdef DIAMETER_DEBUG
|
||||
IPCOM_LOG1(DEBUG, "ipdiameter_setup_ssl_ctx : private key file retrieval succeeded with keyid %s ",
|
||||
ipdiameter.keyfile);
|
||||
#endif /* DIAMETER_DEBUG */
|
||||
|
||||
/* load local node private key file */
|
||||
if(SSL_CTX_use_PrivateKey(ipdiameter.ssl_ctx,private_key) != 1)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_setup_ssl_ctx: failed to load node private key file\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
|
||||
#else /* _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB */
|
||||
|
||||
/* Set up the user password */
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ipdiameter.ssl_ctx,
|
||||
(void*)ipdiameter.keypasswd);
|
||||
|
||||
/* Install the callback to verify the user password */
|
||||
SSL_CTX_set_default_passwd_cb(ipdiameter.ssl_ctx,
|
||||
(void*)ipdiameter_passwd_cb);
|
||||
|
||||
|
||||
/* load local node private key file */
|
||||
if(SSL_CTX_use_PrivateKey_file(ipdiameter.ssl_ctx,
|
||||
ipdiameter.keyfile, SSL_FILETYPE_PEM) != 1)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_setup_ssl_ctx: failed to load node private key file\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_setup_ssl_ctx: loaded key file\n");
|
||||
#endif /* _WRS_CONFIG_IPDIAMETER_SEC_KEY_DB */
|
||||
|
||||
/* set certificate verification flags */
|
||||
#ifdef DIAMETER_DEBUG
|
||||
SSL_CTX_set_verify(ipdiameter.ssl_ctx,
|
||||
SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
ipdiameter_verify_callback);
|
||||
SSL_CTX_set_verify_depth(ipdiameter.ssl_ctx, 4);
|
||||
#endif
|
||||
|
||||
SSL_CTX_set_mode(ipdiameter.ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_session_cache_mode(ipdiameter.ssl_ctx, SSL_SESS_CACHE_OFF);
|
||||
|
||||
/* only accept TLSv1 */
|
||||
SSL_CTX_set_options(ipdiameter.ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 |
|
||||
SSL_OP_NO_SSLv3);
|
||||
|
||||
/* set up cipher list */
|
||||
if (SSL_CTX_set_cipher_list(ipdiameter.ssl_ctx, DIAMETER_CIPHER_LIST) != 1)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_setup_ssl_ctx: failed to set cipher list\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_setup_ssl_ctx: set up cipher list\n");
|
||||
|
||||
IPDIAMETER_LEAVE(retval);
|
||||
|
||||
errout:
|
||||
IPCOM_LOG0(ERR, "ipdiameter_setup_ssl_ctx: failed\n");
|
||||
|
||||
if (ipdiameter.ssl_ctx)
|
||||
{
|
||||
SSL_CTX_free(ipdiameter.ssl_ctx);
|
||||
ipdiameter.ssl_ctx = IP_NULL;
|
||||
}
|
||||
|
||||
leave:
|
||||
IPDIAMETER_UNLOCK();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_tls_connection
|
||||
*===========================================================================
|
||||
* Description: Establish TLS connection over a fd.
|
||||
* Parameters:
|
||||
*
|
||||
*/
|
||||
|
||||
IP_PUBLIC Ip_err
|
||||
ipdiameter_tls_connection(Ipdiameter_peer_entry *peer, Ip_bool connect)
|
||||
{
|
||||
Ip_err retval = IPCOM_SUCCESS;
|
||||
Ip_fd fd = IP_INVALID_SOCKET;
|
||||
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("Calling ipdiameter_tls_connection\n");
|
||||
#endif
|
||||
|
||||
IPDIAMETER_PEER_LOCK(peer);
|
||||
|
||||
IPDIAMETER_LOCK();
|
||||
if (!ipdiameter.tls_enabled || !peer->tls)
|
||||
{
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_tls_connection: no TLS connection\n");
|
||||
#endif
|
||||
/* either we are not or the perr is not TLS enabled, just return */
|
||||
IPDIAMETER_UNLOCK();
|
||||
IPDIAMETER_PEER_UNLOCK(peer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
peer->ssl = SSL_new(ipdiameter.ssl_ctx);
|
||||
IPDIAMETER_UNLOCK();
|
||||
|
||||
if (!peer->ssl)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_tls_connection: SSL_new() failed\n");
|
||||
IPDIAMETER_LEAVE(IPCOM_ERR_FAILED);
|
||||
}
|
||||
|
||||
/* Pick matching IPv4 or IPv6 socket. */
|
||||
#ifdef IPCOM_USE_INET
|
||||
if (peer->peer_addr.sa.sa_family == IP_AF_INET)
|
||||
fd = peer->fd;
|
||||
#endif
|
||||
#ifdef IPCOM_USE_INET6
|
||||
if (peer->peer_addr.sa.sa_family == IP_AF_INET6)
|
||||
fd = peer->fd6;
|
||||
#endif
|
||||
|
||||
(void)SSL_set_fd(peer->ssl, fd);
|
||||
|
||||
/* set SSL state according whether we are initiator or responder */
|
||||
if (connect)
|
||||
{
|
||||
SSL_set_connect_state(peer->ssl);
|
||||
if (SSL_connect(peer->ssl) <= 0)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_tls_connection: SSL_connect() failed\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SSL_set_accept_state(peer->ssl);
|
||||
if (SSL_accept(peer->ssl) <=0)
|
||||
{
|
||||
IPCOM_LOG0(ERR, "ipdiameter_tls_connection: SSL_accept() failed\n");
|
||||
IPDIAMETER_ERROUT(IPCOM_ERR_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_connection: established TLS connection\n");
|
||||
|
||||
IPDIAMETER_LEAVE(retval);
|
||||
|
||||
errout:
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_connection: fail to establish TLS connection\n");
|
||||
|
||||
if(peer->ssl)
|
||||
{
|
||||
SSL_free(peer->ssl);
|
||||
peer->ssl = IP_NULL;
|
||||
}
|
||||
|
||||
leave:
|
||||
IPDIAMETER_PEER_UNLOCK(peer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_tls_read
|
||||
*===========================================================================
|
||||
* Description: Read data from TLS connection.
|
||||
* Parameters:
|
||||
* Return: >0: the number of bytes copied to buf, <=0: error.
|
||||
*
|
||||
*/
|
||||
|
||||
IP_PUBLIC int
|
||||
ipdiameter_tls_read(Ipdiameter_peer_entry *peer, char *buf, int length)
|
||||
{
|
||||
int len, tlserr;
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("Calling ipdiameter_tls_read\n");
|
||||
#endif
|
||||
|
||||
|
||||
IPDIAMETER_PEER_LOCK(peer);
|
||||
|
||||
while(IP_TRUE)
|
||||
{
|
||||
len = SSL_read(peer->ssl, buf, length);
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_tls_read: SSL_read len %d\n", len);
|
||||
#endif
|
||||
if(len <= 0)
|
||||
{
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_tls_read: SSL_read error\n");
|
||||
#endif
|
||||
|
||||
tlserr = SSL_get_error(peer->ssl, len);
|
||||
switch(tlserr) /* an error might mean just retry the read */
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
/* continue the loop */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_read: SSL_ERROR_NONE\n");
|
||||
break;
|
||||
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
/* TLS connection is closed */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_read: SSL_ERROR_ZERO_RETURN\n");
|
||||
len = 0;
|
||||
goto leave;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
/* continue the loop */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_read: SSL_ERROR_WANT_READ\n");
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
/* continue the loop */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_read: SSL_ERROR_WANT_WRITE\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
/* An error occurred, shutdown the connection */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_read: default\n");
|
||||
SSL_shutdown(peer->ssl);
|
||||
len = 0;
|
||||
goto leave;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IPCOM_LOG1(DEBUG, "ipdiameter_tls_read: read in %u bytes data\n", len);
|
||||
goto leave; /* len bytes read */
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
IPDIAMETER_PEER_UNLOCK(peer);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*===========================================================================
|
||||
* ipdiameter_tls_write
|
||||
*===========================================================================
|
||||
* Description: Write data to TLS connection.
|
||||
* Parameters:
|
||||
* Return: >0: the number of bytes copied to buf, <=0: error.
|
||||
*
|
||||
*/
|
||||
|
||||
IP_PUBLIC int
|
||||
ipdiameter_tls_write(SSL *ssl, char *buf, int length)
|
||||
{
|
||||
int len, tlserr;
|
||||
|
||||
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("Calling ipdiameter_tls_write\n");
|
||||
#endif
|
||||
|
||||
while(IP_TRUE)
|
||||
{
|
||||
len = SSL_write(ssl, buf, length);
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_tls_write, SSL_wirte len %d\n", len);
|
||||
#endif
|
||||
if(len <= 0)
|
||||
{
|
||||
#ifdef DIAMETER_DEBUG
|
||||
ipcom_printf("ipdiameter_tls_write: SSL_write() error\n");
|
||||
#endif
|
||||
|
||||
tlserr = SSL_get_error(ssl, len);
|
||||
switch(tlserr) /* an error might mean just retry the read */
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
/* continue the loop */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_write: SSL_ERROR_NONE\n");
|
||||
break;
|
||||
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
/* TLS connection is closed */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_write: SSL_ERROR_ZERO_RETURN\n")
|
||||
;
|
||||
len = 0;
|
||||
goto leave;
|
||||
|
||||
case SSL_ERROR_WANT_READ:
|
||||
/* continue the loop */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_write: SSL_ERROR_WANT_READ\n");
|
||||
break;
|
||||
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
/* continue the loop */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_write: SSL_ERROR_WANT_WRITE\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
/* An error occurred, shutdown the connection */
|
||||
IPCOM_LOG0(DEBUG, "ipdiameter_tls_write: default\n");
|
||||
SSL_shutdown(ssl);
|
||||
len = 0;
|
||||
goto leave;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IPCOM_LOG1(DEBUG, "ipdiameter_tls_write: write out %u bytes data\n", len);
|
||||
goto leave; /* len bytes read */
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
#endif /* IPSSL */
|
||||
|
||||
/*
|
||||
****************************************************************************
|
||||
* END OF FILE
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user