1414 lines
58 KiB
C
1414 lines
58 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipha_aaa_diameter.c,v $ $Revision: 1.5.16.4 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmipha/config/ipmipha_aaa_diameter.c,v $
|
|
* $Author: jsheng $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipmipha_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPMIPHA_DIAMETER_ENABLE
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_ipd.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock2.h>
|
|
#include <ipcom_syslog.h>
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_sysvar.h>
|
|
#include <private/ipmip_timer.h>
|
|
|
|
#include <ipmip4.h>
|
|
#include <private/ipmip4_context.h>
|
|
#include <private/ipmip4_util.h>
|
|
#include <private/ipmip4_sysext.h>
|
|
#include <private/ipmip4_auth.h>
|
|
#include <private/ipmip4_pkt.h>
|
|
#include <private/ipmip4_pktbuf.h>
|
|
#include <private/ipmip4_diameter.h>
|
|
|
|
#include "ipmipha.h"
|
|
#include "ipmipha_h.h"
|
|
#include "ipmipha_attr_h.h"
|
|
#include "ipmipha_if.h"
|
|
#include "ipmipha_reg.h"
|
|
#include "ipmipha_node.h"
|
|
#include "ipmipha_pktbuf.h"
|
|
|
|
#include <ipdiameter.h>
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPMIPHA_AAA_DIAMETER "AAA-DIAMETER"
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
typedef struct Ipmipha_aaa_diameter_config_ifp
|
|
{
|
|
struct Ipmip4_diameter_context *diameter;
|
|
/* Should the MN-AAA authentication extension be verified? */
|
|
Ip_bool access;
|
|
/* MUST the MN-AAA extension be available? */
|
|
Ip_bool access_require;
|
|
Ip_u32 access_timeout;
|
|
|
|
Ipmipha_data_t *data;
|
|
} Ipmipha_aaa_diameter_config_ifp_t;
|
|
|
|
typedef struct Ipmipha_aaa_diameter_pktbuf_data
|
|
{
|
|
/**/
|
|
void *session_id;
|
|
Ip_size_t session_id_length;
|
|
|
|
/**/
|
|
void *origin_host;
|
|
Ip_size_t origin_host_length;
|
|
|
|
void *peer;
|
|
|
|
Ip_u32 hbh_id;
|
|
Ip_u32 e2e_id;
|
|
|
|
Ip_u32 mn_fa_spi;
|
|
Ip_u32 fa_ha_spi;
|
|
Ip_u32 feature;
|
|
|
|
Ip_bool mn_ha_keyreq;
|
|
Ip_u8 *mn_ha_keyreq_nonce;
|
|
Ip_size_t mn_ha_keyreq_nonce_len;
|
|
Ip_u8 *mn_ha_keyreq_key;
|
|
Ip_size_t mn_ha_keyreq_key_len;
|
|
Ip_u32 mn_ha_keyreq_key_spi;
|
|
|
|
Ip_bool mn_fa_keyreq;
|
|
Ip_u8 *mn_fa_keyreq_nonce;
|
|
Ip_size_t mn_fa_keyreq_nonce_len;
|
|
Ip_u32 mn_fa_keyreq_key_spi;
|
|
|
|
Ip_bool fa_ha_keyreq;
|
|
Ip_u8 *fa_ha_keyreq_key;
|
|
Ip_size_t fa_ha_keyreq_key_len;
|
|
Ip_u32 fa_ha_keyreq_key_spi;
|
|
|
|
} Ipmipha_aaa_diameter_pktbuf_data_t;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
static Ipmipha_extension_t ipmipha_aaa_diameter_srv;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_pktaux_free(struct Ipmipha_data *data,
|
|
struct Ipmip_proc *proc,
|
|
struct Ipmipha_pktbuf *pbuf,
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(pbuf);
|
|
if (aaa->origin_host)
|
|
ipcom_free(aaa->origin_host);
|
|
if (aaa->session_id)
|
|
ipcom_free(aaa->session_id);
|
|
if (aaa->mn_ha_keyreq_nonce)
|
|
ipcom_free(aaa->mn_ha_keyreq_nonce);
|
|
if (aaa->mn_ha_keyreq_key)
|
|
ipcom_free(aaa->mn_ha_keyreq_key);
|
|
if (aaa->mn_fa_keyreq_nonce)
|
|
ipcom_free(aaa->mn_fa_keyreq_nonce);
|
|
if (aaa->fa_ha_keyreq_key)
|
|
ipcom_free(aaa->fa_ha_keyreq_key);
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_HAA(struct Ipmipha_data *data,
|
|
struct Ipmip_proc *proc,
|
|
void *global_config,
|
|
Ipmipha_aaa_diameter_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
Ipmipha_node_t *node,
|
|
struct Ipmipha_pktbuf *req_pbuf,
|
|
struct Ipmipha_pktbuf *rep_pbuf)
|
|
{
|
|
Ipdiameter_header *packet;
|
|
Ip_u32 result_code = DIAMETER_SUCCESS;
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&data->ipmip4.ipmip, &req_pbuf->ipmip4.ipmip, ipmipha_aaa_diameter_srv.pktaux.pktbuf_data_index, IP_FALSE);
|
|
if(IP_NULL == aaa)
|
|
return;
|
|
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
|
|
if (!ipmip4_diameter_answer_alloc(&data->ipmip4, proc, ifp_config->diameter, aaa->session_id, aaa->session_id_length, aaa->hbh_id, aaa->e2e_id, &packet))
|
|
return;
|
|
|
|
/* Set comand code to IPRADIUS_CODE_Access_Request */
|
|
ipdiameter_set_hdr_code((Ip_u32 *)packet, DIAMETER_CODE_Home_Agent_MIP_Answer);
|
|
|
|
/***** Add attributes here! *****/
|
|
if (req_pbuf->ipmip4.ext.mobile.nai_mobile != IP_NULL)
|
|
(void)ipdiameter_avp_add_array(packet,
|
|
DIAMETER_AVP_CODE_User_Name,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
(Ip_u8*)IPMIP4_MSGEXT_SHDR_EXT_DATA(req_pbuf->ipmip4.ext.mobile.nai_mobile),
|
|
(Ip_u8)IPMIP4_MSGEXT_SHDR_EXT_SIZE(req_pbuf->ipmip4.ext.mobile.nai_mobile));
|
|
|
|
|
|
if (req_pbuf->pktinfo.haBindingHomeAddress != 0)
|
|
{
|
|
union Ip_sockaddr_union s_un;
|
|
|
|
ipcom_memset(&s_un, 0, sizeof(s_un));
|
|
|
|
s_un.sin.sin_addr.s_addr = req_pbuf->pktinfo.haBindingHomeAddress;
|
|
s_un.sin.sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(&s_un.sin, sizeof(s_un.sin));
|
|
|
|
(void)ipdiameter_avp_add_ip_address(packet,
|
|
DIAMETER_AVP_CODE_MIP_Mobile_Node_Address,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
s_un);
|
|
}
|
|
|
|
{
|
|
union Ip_sockaddr_union s_un;
|
|
|
|
ipcom_memset(&s_un, 0, sizeof(s_un));
|
|
|
|
s_un.sin.sin_addr.s_addr = req_pbuf->pktinfo.haBindingHomeAgentAddress;
|
|
s_un.sin.sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(&s_un.sin, sizeof(s_un.sin));
|
|
|
|
(void)ipdiameter_avp_add_ip_address(packet,
|
|
DIAMETER_AVP_CODE_MIP_Home_Agent_Address,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
s_un);
|
|
}
|
|
|
|
(void)ipdiameter_avp_add_array(packet,
|
|
DIAMETER_AVP_CODE_MIP_Reg_Reply,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
IPMIP_BUFFER_DATA(&rep_pbuf->ipmip4.ipmip.packet),
|
|
IPMIP_BUFFER_SIZE(&rep_pbuf->ipmip4.ipmip.packet));
|
|
|
|
if (aaa->mn_fa_spi != 0)
|
|
ipdiameter_avp_add_u32(packet, DIAMETER_AVP_CODE_MIP_FA_to_MN_SPI, DIAMETER_AVP_M_FLAG, IP_NULL, aaa->mn_fa_spi);
|
|
if (aaa->fa_ha_spi != 0)
|
|
ipdiameter_avp_add_u32(packet, DIAMETER_AVP_CODE_MIP_FA_to_HA_SPI, DIAMETER_AVP_M_FLAG, IP_NULL, aaa->fa_ha_spi);
|
|
|
|
|
|
/*
|
|
if (pbuf->pktinfo.haBindingHAErrorCode != 0)
|
|
result_code = 4005;
|
|
*/
|
|
ipdiameter_avp_add_u32(packet, DIAMETER_AVP_CODE_Result_Code, DIAMETER_AVP_M_FLAG, IP_NULL, result_code);
|
|
|
|
if (req_pbuf->ipmip4.ipmip.message == IP_NULL)
|
|
req_pbuf->haBindingAAAVerified = IP_TRUE;
|
|
|
|
/* Add application id */
|
|
(void)ipdiameter_peer_pkt_send(aaa->peer, packet);
|
|
ipdiameter_answer_pkt_free(packet);
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_pkt_rep_mobile_home(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
void *global_config,
|
|
Ipmipha_aaa_diameter_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipha_node *node,
|
|
struct Ipmipha_pktbuf *req_pbuf,
|
|
struct Ipmipha_pktbuf *pbuf)
|
|
{
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&ctx->ipmip4.ipmip, &req_pbuf->ipmip4.ipmip, ipmipha_aaa_diameter_srv.pktaux.pktbuf_data_index, IP_FALSE);
|
|
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(ifp_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
|
|
if (aaa)
|
|
{
|
|
Ipmip4_ext_gen_auth_t *auth = (Ipmip4_ext_gen_auth_t *)req_pbuf->ipmip4.ext.mobile.mn_aaa;
|
|
Ipmip4_ext_keyrep_ha_t *keyrep = (Ipmip4_ext_keyrep_ha_t *)proc->ntop.ntop_pbuf;
|
|
Ip_u32 aaa_spi = IP_GET_NTOHL(&auth->spi[0]);
|
|
|
|
if (aaa->mn_ha_keyreq)
|
|
{
|
|
|
|
ipcom_memset(keyrep, 0, sizeof(*keyrep));
|
|
/**/
|
|
keyrep->type = IPMIP4_EXT_TYPE_MN_HA_KEYGEN_REP;
|
|
keyrep->subtype = IPMIP4_KEYGEN_SUBTYPE_1;
|
|
IP_SET_HTONL(&keyrep->lifetime, 0xffffffff);
|
|
IP_SET_HTONS(&keyrep->alg_id, IPMIP4_AUTH_ALG_HMAC_SHA);
|
|
IP_SET_HTONS(&keyrep->replay, 2);
|
|
IP_SET_HTONL(&keyrep->aaa_spi, aaa_spi);
|
|
IP_SET_HTONS(&keyrep->length, (IPMIP4_EXT_KEYREP_HA_LENGTH + aaa->mn_ha_keyreq_nonce_len - IPMIP4_MSGEXT_LHDR_HDR_SIZE));
|
|
IP_SET_HTONL(&keyrep->spi, aaa->mn_ha_keyreq_key_spi);
|
|
|
|
/* Copy the nonce */
|
|
ipcom_memcpy(keyrep->nonce, aaa->mn_ha_keyreq_nonce, aaa->mn_ha_keyreq_nonce_len);
|
|
|
|
/* Append */
|
|
ipmip4_msgext_buffer_append_lhdr(&pbuf->ipmip4.ipmip.packet, (void *)proc->ntop.ntop_pbuf);
|
|
}
|
|
|
|
if (aaa->mn_fa_keyreq)
|
|
{
|
|
ipcom_memset(keyrep, 0, sizeof(*keyrep));
|
|
|
|
keyrep->type = IPMIP4_EXT_TYPE_MN_FA_KEYGEN_REP;
|
|
keyrep->subtype = IPMIP4_KEYGEN_SUBTYPE_1;
|
|
|
|
IP_SET_HTONL(&keyrep->lifetime, 0xffffffff);
|
|
IP_SET_HTONS(&keyrep->alg_id, IPMIP4_AUTH_ALG_HMAC_SHA);
|
|
IP_SET_HTONL(&keyrep->aaa_spi, aaa_spi);
|
|
|
|
IP_SET_HTONL(&keyrep->spi, aaa->mn_fa_keyreq_key_spi);
|
|
/**/
|
|
IP_SET_HTONS(&keyrep->length, (IPMIP4_EXT_KEYREP_FA_LENGTH + aaa->mn_fa_keyreq_nonce_len - IPMIP4_MSGEXT_LHDR_HDR_SIZE));
|
|
|
|
/* Copy the nonce */
|
|
ipcom_memcpy(keyrep->nonce, aaa->mn_fa_keyreq_nonce, aaa->mn_fa_keyreq_nonce_len);
|
|
|
|
/* Append */
|
|
ipmip4_msgext_buffer_append_lhdr(&pbuf->ipmip4.ipmip.packet, (void *)proc->ntop.ntop_pbuf);
|
|
}
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diamater_mn_ha_keyreq_create(Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa,
|
|
Ipmipha_node_t *node,
|
|
Ipmipha_pktbuf_t *pbuf)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(pbuf);
|
|
|
|
if (node->haBindingHomeSA)
|
|
ipmip4_auth_spi_free(node->haBindingHomeSA);
|
|
|
|
node->haBindingHomeSA = ipmip4_auth_spi_create(proc, aaa->mn_ha_keyreq_key_spi, aaa->mn_ha_keyreq_key, aaa->mn_ha_keyreq_key_len, IPMIP4_AUTH_METHOD_MD5_HMAC);
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_parse_mn_ha_keyreq(Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa,
|
|
Ipmipha_pktbuf_t *pbuf,
|
|
struct Ipdiameter_header_struct *response_packet_v)
|
|
{
|
|
Ip_u32 len;
|
|
Ip_u8 *val;
|
|
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
if (ipdiameter_get_avp(response_packet_v, DIAMETER_AVP_CODE_MIP_MN_to_HA_MSA, &len, &val) == IPCOM_SUCCESS)
|
|
{
|
|
Ip_u32 avp_len;
|
|
Ip_u8 *avp;
|
|
Ip_u32 nonce_len;
|
|
Ip_u8 *nonce_avp;
|
|
Ip_u32 key_len;
|
|
Ip_u8 *key_avp;
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Algorithm_Type, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
if (IP_GET_NTOHL(avp) != 2)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Only the HMAC-SHA1 (2) Algorithm Type is supported");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Algorithm Type AVP in MIP-MN-to-HA-MSA is missing");
|
|
return;
|
|
}
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Replay_Mode, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
if (IP_GET_NTOHL(avp) != 2)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Only the Timestamp (2) Replay-Mode is supported");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Replay-Mode AVP in MIP-MN-to-HA-MSA is missing or truncated");
|
|
return;
|
|
}
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Nonce, &nonce_len, &nonce_avp) != IPCOM_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER MIP-Nonce AVP in MIP-MN-to-HA-MSA is missing");
|
|
return;
|
|
}
|
|
|
|
if (ipdiameter_get_avp(response_packet_v, DIAMETER_AVP_CODE_MIP_HA_to_MN_MSA, &len, &val) == IPCOM_SUCCESS)
|
|
{
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Algorithm_Type, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
if (IP_GET_NTOHL(avp) != 2)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Only the HMAC-SHA1 (2) Algorithm Type is supported");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Algorithm Type AVP in MIP-HA-to-MN-MSA is missing or truncated");
|
|
return;
|
|
}
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Replay_Mode, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
if (IP_GET_NTOHL(avp) != 2)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Only the Timestamp (2) Replay Type is supported");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Replay-Mode AVP in MIP-HA-to-MN-MSA is missing or truncated");
|
|
return;
|
|
}
|
|
|
|
/**/
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Session_Key, &key_len, &key_avp) != IPCOM_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Session-Key AVP in MIP-HA-to-MN-MSA is missing");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Ipmip4_ext_keyreq_t *keyreq = (Ipmip4_ext_keyreq_t *)pbuf->ipmip4.ext.mobile.mn_ha_keyreq;
|
|
|
|
aaa->mn_ha_keyreq = IP_TRUE;
|
|
aaa->mn_ha_keyreq_nonce_len = nonce_len;
|
|
ipmip_util_dup(&aaa->mn_ha_keyreq_nonce, nonce_avp, nonce_len);
|
|
aaa->mn_ha_keyreq_key_len = key_len;
|
|
ipmip_util_dup(&aaa->mn_ha_keyreq_key, key_avp, key_len);
|
|
if (keyreq != IP_NULL)
|
|
aaa->mn_ha_keyreq_key_spi = IP_GET_NTOHL(&keyreq->spi);
|
|
else
|
|
{
|
|
aaa->mn_ha_keyreq_key_spi = ipcom_random() + 256;
|
|
aaa->mn_ha_keyreq_key_spi = IP_MAX(256, aaa->mn_ha_keyreq_key_spi);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER MIP-HA-to-MN-MSA is missing but MIP-MN-to-HA-MSA was specified");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER MIP-MN-to-HA-MSA is missing but KEYREQ was present in registration");
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_parse_mn_fa_keyreq(Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa,
|
|
Ipmipha_pktbuf_t *pbuf,
|
|
struct Ipdiameter_header_struct *response_packet_v)
|
|
{
|
|
Ip_u32 len;
|
|
Ip_u8 *val;
|
|
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
if (ipdiameter_get_avp(response_packet_v, DIAMETER_AVP_CODE_MIP_MN_to_FA_MSA, &len, &val) == IPCOM_SUCCESS)
|
|
{
|
|
Ip_u32 avp_len;
|
|
Ip_u8 *avp;
|
|
Ip_u32 nonce_len;
|
|
Ip_u8 *nonce_avp;
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Algorithm_Type, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
if (IP_GET_NTOHL(avp) != 2)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Only the HMAC-SHA1 (2) Algorithm Type is supported");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Algorithm Type AVP in MIP-MN-to-FA-MSA is missing");
|
|
return;
|
|
}
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_FA_to_MN_SPI, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
aaa->mn_fa_keyreq_key_spi = IP_GET_NTOHL(avp);
|
|
}
|
|
else
|
|
{
|
|
Ipmip4_ext_keyreq_t *keyreq = (Ipmip4_ext_keyreq_t *)pbuf->ipmip4.ext.mobile.mn_fa_keyreq;
|
|
if (keyreq != IP_NULL)
|
|
aaa->mn_fa_keyreq_key_spi = IP_GET_NTOHL(&keyreq->spi);
|
|
else
|
|
{
|
|
aaa->mn_fa_keyreq_key_spi = ipcom_random() + 256;
|
|
aaa->mn_fa_keyreq_key_spi = IP_MAX(256, aaa->mn_fa_keyreq_key_spi);
|
|
}
|
|
}
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Nonce, &nonce_len, &nonce_avp) != IPCOM_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER MIP-Nonce AVP in MIP-MN-to-FA-MSA is missing");
|
|
return;
|
|
}
|
|
|
|
aaa->mn_fa_keyreq = IP_TRUE;
|
|
aaa->mn_fa_keyreq_nonce_len = nonce_len;
|
|
ipmip_util_dup(&aaa->mn_fa_keyreq_nonce, nonce_avp, nonce_len);
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER MIP-MN-to-FA-MSA is missing, but flagged in feature vector");
|
|
return;
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_parse_fa_ha_keyreq(Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa,
|
|
Ipmipha_pktbuf_t *pbuf,
|
|
struct Ipdiameter_header_struct *response_packet_v)
|
|
{
|
|
Ip_u32 len;
|
|
Ip_u8 *val;
|
|
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
if (ipdiameter_get_avp(response_packet_v, DIAMETER_AVP_CODE_MIP_HA_to_FA_MSA, &len, &val) == IPCOM_SUCCESS)
|
|
{
|
|
Ip_u32 avp_len;
|
|
Ip_u8 *avp;
|
|
Ip_u32 key_len;
|
|
Ip_u8 *key_avp;
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Algorithm_Type, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
if (IP_GET_NTOHL(avp) != 2)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Only the HMAC-SHA1 (2) Algorithm Type is supported");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Algorithm Type AVP in MIP-HA-to-FA-MSA is missing");
|
|
return;
|
|
}
|
|
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_HA_to_FA_SPI, &avp_len, &avp) == IPCOM_SUCCESS && avp_len >= 4)
|
|
{
|
|
aaa->fa_ha_keyreq_key_spi = IP_GET_NTOHL(avp);
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Ha-to-FA-SPI in MIP-HA-to-FA-MSA is missing");
|
|
return;
|
|
}
|
|
|
|
/**/
|
|
if (ipdiameter_grouped_avp_get_avp(val, len, DIAMETER_AVP_CODE_MIP_Session_Key, &key_len, &key_avp) != IPCOM_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Session-Key AVP in MIP-FA-to-HA-MSA is missing");
|
|
return;
|
|
}
|
|
|
|
aaa->fa_ha_keyreq = IP_TRUE;
|
|
ipmip_util_dup(&aaa->fa_ha_keyreq_key, key_avp, key_len);
|
|
aaa->fa_ha_keyreq_key_len = key_len;
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER MIP-FA-to-HA-MSA is missing but KEYREQ was present in registration");
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_AMA(int result,
|
|
Ipmipha_data_t *data,
|
|
Ipmip_proc_t *proc,
|
|
struct Ipmip4_diameter_context *diameter,
|
|
Ipmipha_pktbuf_t *pbuf,
|
|
Ipmipha_node_t *node,
|
|
struct Ipdiameter_request_struct *request_v,
|
|
struct Ipdiameter_header_struct *request_packet_v,
|
|
struct Ipdiameter_header_struct *response_packet_v)
|
|
{
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&data->ipmip4.ipmip, &pbuf->ipmip4.ipmip, ipmipha_aaa_diameter_srv.pktaux.pktbuf_data_index, IP_TRUE);
|
|
if(IP_NULL == aaa)
|
|
return;
|
|
|
|
IPMIP_UNUSED_PARAMETER(diameter);
|
|
IPMIP_UNUSED_PARAMETER(request_v);
|
|
IPMIP_UNUSED_PARAMETER(request_packet_v);
|
|
if (result == IPMIP4_DIAMETER_ACCESS_REQUEST_SUCCESS)
|
|
{
|
|
/* Time to resolve the AVP's */
|
|
Ip_u32 len;
|
|
Ip_u8 *val;
|
|
int tmp;
|
|
|
|
if (ipdiameter_get_avp(response_packet_v, DIAMETER_AVP_CODE_Result_Code, &len, &val) != IPCOM_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Result-Code AVP not present. Poorly formed");
|
|
goto error_out;
|
|
}
|
|
|
|
/* Read the value */
|
|
tmp = IP_GET_HTONL(val);
|
|
if (tmp != DIAMETER_SUCCESS && tmp != DIAMETER_LIMITED_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Result-Code AVP reported error %d", tmp);
|
|
goto error_out;
|
|
}
|
|
|
|
/* Retrieve the mandatory information */
|
|
if (ipdiameter_get_avp(response_packet_v, DIAMETER_AVP_CODE_MIP_Home_Agent_Address, &len, &val) != IPCOM_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Home Agent Address AVP not present. Poorly formed");
|
|
goto error_out;
|
|
}
|
|
|
|
/* Retrieve the address */
|
|
pbuf->pktinfo.haBindingResolvedHomeAgentAddress = IP_GET_32ON8((val + 2));
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s Diameter Extension: Mip-Home-Agent-Address = %s",
|
|
ipmipha_node_describe(proc, node, IP_NULL),
|
|
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingResolvedHomeAgentAddress)));
|
|
|
|
|
|
/* Retrieve the mandatory information */
|
|
if (ipdiameter_get_avp(response_packet_v, DIAMETER_AVP_CODE_MIP_Mobile_Node_Address, &len, &val) != IPCOM_SUCCESS)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER Mobile Node Address AVP not present. Poorly formed");
|
|
goto error_out;
|
|
}
|
|
|
|
/* Retrieve the address */
|
|
pbuf->pktinfo.haBindingResolvedHomeAddress = IP_GET_32ON8((val + 2));
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s Diameter Extension: Mip-Mobile-Node-Address = %s",
|
|
ipmipha_node_describe(proc, node, pbuf->binding),
|
|
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingResolvedHomeAddress)));
|
|
|
|
/* Parse the keyreq */
|
|
if (pbuf->ipmip4.ext.mobile.mn_ha_keyreq != IP_NULL)
|
|
{
|
|
ipmipha_aaa_diameter_parse_mn_ha_keyreq(data, proc, aaa, pbuf, response_packet_v);
|
|
if (pbuf->ipmip4.ipmip.message == IP_NULL)
|
|
ipmipha_aaa_diamater_mn_ha_keyreq_create(data, proc, aaa, node, pbuf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"AAA DIAMETER authentication request failed");
|
|
}
|
|
|
|
error_out:
|
|
/* Are we satisfied? */
|
|
if (pbuf->ipmip4.ipmip.message == IP_NULL)
|
|
{
|
|
if (node->nai_aaah == IP_NULL && aaa->origin_host != IP_NULL)
|
|
node->nai_aaah = (Ipmip4_msgext_uhdr_t *)ipmip4_sysext_nai_aaah_create(aaa->origin_host, aaa->origin_host_length);
|
|
pbuf->haBindingAAAVerified = IP_TRUE;
|
|
}
|
|
|
|
ipmip_timer_execute(&data->ipmip4.ipmip, &node->service);
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipha_aaa_diameter_access_request(struct Ipmipha_data *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipha_aaa_diameter_config_ifp_t *ifp_config,
|
|
struct Ipmipha_node *node,
|
|
Ipmipha_pktbuf_t *pbuf)
|
|
{
|
|
Ipdiameter_header *packet;
|
|
Ipdiameter_request request;
|
|
|
|
Ip_u32 feature = IPMIP4_DIAMETER_FEATURE_CO_LOCATED_MN;
|
|
|
|
if (!ipmip4_diameter_request_alloc(&data->ipmip4, proc, ifp_config->diameter, &request, &packet))
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"DIAMETER unable to allocate request packet");
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/* Set comand code to IPRADIUS_CODE_Access_Request */
|
|
ipdiameter_set_hdr_code((Ip_u32 *)packet, DIAMETER_CODE_AA_Mobile_Node_Request);
|
|
|
|
/***** Add attributes here! *****/
|
|
if (pbuf->ipmip4.ext.mobile.nai_mobile != IP_NULL)
|
|
(void)ipdiameter_avp_add_array(packet,
|
|
DIAMETER_AVP_CODE_User_Name,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
(Ip_u8*)IPMIP4_MSGEXT_SHDR_EXT_DATA(pbuf->ipmip4.ext.mobile.nai_mobile),
|
|
(Ip_u8)IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ipmip4.ext.mobile.nai_mobile));
|
|
|
|
|
|
if (pbuf->pktinfo.haBindingHomeAddress != 0)
|
|
{
|
|
union Ip_sockaddr_union s_un;
|
|
|
|
ipcom_memset(&s_un, 0, sizeof(s_un));
|
|
|
|
s_un.sin.sin_addr.s_addr = pbuf->pktinfo.haBindingHomeAddress;
|
|
s_un.sin.sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(&s_un.sin, sizeof(s_un.sin));
|
|
|
|
feature |= IPMIP4_DIAMETER_FEATURE_MN_HOA_REQ;
|
|
(void)ipdiameter_avp_add_ip_address(packet,
|
|
DIAMETER_AVP_CODE_MIP_Mobile_Node_Address,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
s_un);
|
|
}
|
|
|
|
if (pbuf->pktinfo.haBindingHomeAgentAddress == 0)
|
|
feature |= IPMIP4_DIAMETER_FEATURE_HA_REQ;
|
|
else if (pbuf->pktinfo.haBindingHomeAgentAddress == 0xffffffff)
|
|
feature |= IPMIP4_DIAMETER_FEATURE_HA_REQ|IPMIP4_DIAMETER_FEATURE_HOA_IN_HOME_REALM;
|
|
else
|
|
{
|
|
union Ip_sockaddr_union s_un;
|
|
|
|
ipcom_memset(&s_un, 0, sizeof(s_un));
|
|
|
|
s_un.sin.sin_addr.s_addr = pbuf->pktinfo.haBindingHomeAgentAddress;
|
|
s_un.sin.sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(&s_un.sin, sizeof(s_un.sin));
|
|
|
|
(void)ipdiameter_avp_add_ip_address(packet,
|
|
DIAMETER_AVP_CODE_MIP_Home_Agent_Address,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
s_un);
|
|
}
|
|
|
|
(void)ipdiameter_avp_add_array(packet,
|
|
DIAMETER_AVP_CODE_MIP_Reg_Request,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet),
|
|
IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet));
|
|
|
|
if (pbuf->ipmip4.ext.mobile.mn_ha_keyreq != IP_NULL)
|
|
feature |= IPMIP4_DIAMETER_FEATURE_MN_HA_KEYREQ;
|
|
|
|
ipdiameter_avp_add_u32(packet,
|
|
DIAMETER_AVP_CODE_MIP_Feature_Vector,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
feature);
|
|
|
|
if (pbuf->ipmip4.ext.mobile.challenge != IP_NULL)
|
|
(void)ipdiameter_avp_add_array(packet,
|
|
DIAMETER_AVP_CODE_MIP_FA_Challenge,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
IPMIP4_MSGEXT_SHDR_EXT_DATA(pbuf->ipmip4.ext.mobile.challenge),
|
|
IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ipmip4.ext.mobile.challenge));
|
|
|
|
/* Add the AAA grouped */
|
|
{
|
|
Ipmip4_ext_gen_auth_t *auth = (Ipmip4_ext_gen_auth_t *)pbuf->ipmip4.ext.mobile.mn_aaa;
|
|
Ip_u32 tval;
|
|
Ipdiameter_header *grouped = ipdiameter_request_pkt_malloc(0);
|
|
|
|
/**/
|
|
if (grouped == IP_NULL)
|
|
{
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"DIAMETER unable to allocate grouped packet");
|
|
ipdiameter_request_pkt_free(packet);
|
|
return IP_FALSE;
|
|
}
|
|
|
|
tval = IP_GET_NTOHL(&auth->spi[0]);
|
|
ipdiameter_avp_add_u32(grouped,
|
|
DIAMETER_AVP_CODE_MIP_MN_AAA_SPI,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
tval);
|
|
|
|
/* Size of request */
|
|
tval = (Ip_u8 *)auth->authenticator - (Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet);
|
|
ipdiameter_avp_add_u32(grouped,
|
|
DIAMETER_AVP_CODE_MIP_Auth_Input_Data_Length,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
tval);
|
|
|
|
ipdiameter_avp_add_u32(grouped,
|
|
DIAMETER_AVP_CODE_MIP_Authenticator_Offset,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
tval);
|
|
|
|
tval = IP_GET_NTOHS(&auth->length) - 4;
|
|
ipdiameter_avp_add_u32(grouped,
|
|
DIAMETER_AVP_CODE_MIP_Authenticator_Length,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
tval);
|
|
|
|
tval = ipdiameter_get_hdr_length((Ip_u32 *)grouped) - IPDIAMETER_HDRSIZE;
|
|
(void)ipdiameter_avp_add_array(packet,
|
|
DIAMETER_AVP_CODE_MIP_MN_AAA_Auth,
|
|
DIAMETER_AVP_M_FLAG,
|
|
IP_NULL,
|
|
grouped->avp,
|
|
tval);
|
|
ipdiameter_request_pkt_free(grouped);
|
|
}
|
|
|
|
|
|
/* Add application id */
|
|
return ipmip4_diameter_access_request(&data->ipmip4,
|
|
proc,
|
|
ifp_config->diameter,
|
|
(Ipmip4_diameter_func_t)ipmipha_aaa_diameter_AMA,
|
|
&pbuf->ipmip4,
|
|
node,
|
|
&request,
|
|
packet,
|
|
0);
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipha_diameter_auth
|
|
*===========================================================================
|
|
* Description: Resolve a mobile-AAA extension using DIAMETER
|
|
* Parameters: ctx - Context
|
|
* proc - Current process
|
|
* setup - Setup structure
|
|
* ifcfg - Setup structure for current interface.
|
|
* pbuf - The container.
|
|
* lock - Timer lock
|
|
* func - Timer function callback
|
|
* Returns: One of IPMIP4_RETCODE_CONTINUE, IPMIP4_RETCODE_SKIPPED or
|
|
* IPMIP4_RETCODE_PENDING
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipmipha_aaa_diameter_pkt_req_verify(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
void *global_config,
|
|
Ipmipha_aaa_diameter_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipha_node *node,
|
|
struct Ipmipha_pktbuf *pbuf)
|
|
{
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa = ipmip_pktbuf_pktaux_data_get(&ctx->ipmip4.ipmip, &pbuf->ipmip4.ipmip, ipmipha_aaa_diameter_srv.pktaux.pktbuf_data_index, IP_FALSE);
|
|
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
|
|
if (aaa)
|
|
{
|
|
if (aaa->mn_ha_keyreq)
|
|
ipmipha_aaa_diamater_mn_ha_keyreq_create(ctx, proc, aaa, node, pbuf);
|
|
if (aaa->fa_ha_keyreq)
|
|
pbuf->haBindingForeignSA = ipmip4_auth_spi_create(proc, aaa->fa_ha_keyreq_key_spi, aaa->fa_ha_keyreq_key, aaa->fa_ha_keyreq_key_len, IPMIP4_AUTH_METHOD_MD5_HMAC);
|
|
|
|
/* Are we satisfied? */
|
|
if (node->nai_aaah == IP_NULL && aaa->origin_host != IP_NULL)
|
|
node->nai_aaah = (Ipmip4_msgext_uhdr_t *)ipmip4_sysext_nai_aaah_create(aaa->origin_host, aaa->origin_host_length);
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
if (ifp_config->access)
|
|
{
|
|
/* Do access */
|
|
if (pbuf->ipmip4.ext.mobile.mn_aaa != IP_NULL)
|
|
{
|
|
Ipmip4_ext_gen_auth_t *auth = (Ipmip4_ext_gen_auth_t *)pbuf->ipmip4.ext.mobile.mn_aaa;
|
|
Ip_u32 spi = IP_GET_NTOHL(&auth->spi[0]);
|
|
Ip_time_t now = ipmip_util_time();
|
|
|
|
pbuf->pktinfo.haBindingSPIMobileAAA = spi;
|
|
|
|
/**/
|
|
if ((now - pbuf->node->haNodeAAAVerificationTime) < ifp_config->access_timeout)
|
|
{
|
|
/* Verify keygen; if we have keygen in play, the keygen must match */
|
|
if (pbuf->ipmip4.ext.mobile.mn_ha_keyreq == IP_NULL)
|
|
{
|
|
/* If not keygen; there has to be security association's that correspond to the overall security policy */
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&ctx->ipmip4.ipmip,
|
|
proc,
|
|
"Node %s previous diameter authorization still valid",
|
|
ipmipha_node_describe(proc, pbuf->node, pbuf->binding)));
|
|
|
|
if (pbuf->pktinfo.haBindingForeignHomeSAPolicyOK != 0 && pbuf->pktinfo.haBindingMobileHomeSAPolicyOK != 0)
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
}
|
|
else if (ifp_config->access_require)
|
|
{
|
|
/* Required MN-AAA; but it wasn't there */
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"HA required MN-AAA, but it was not provided");
|
|
return IP_FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Continue */
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/* OK; we've setup the message structure; time to invoke the access request */
|
|
if (!ipmipha_aaa_diameter_access_request(ctx, proc, ifp_config, node, pbuf))
|
|
{
|
|
if (pbuf->ipmip4.ipmip.message == IP_NULL)
|
|
ipmip_pktbuf_error(&pbuf->ipmip4.ipmip,
|
|
0,
|
|
"HA not able to communicate with DIAMETER server");
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipha_diameter_HAR_recv
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_HAR_recv(Ipmipha_aaa_diameter_config_ifp_t *ifp_config,
|
|
void *req,
|
|
void *peer)
|
|
{
|
|
Ipdiameter_header *hdr = req;
|
|
Ipmipha_data_t *data = ifp_config->data;
|
|
|
|
/* Do we have diameter enabled? */
|
|
if (data->conf != IP_NULL)
|
|
{
|
|
/* Time to resolve the AVP's */
|
|
Ip_u32 len;
|
|
Ip_u8 *val;
|
|
Ipmipha_aaa_diameter_pktbuf_data_t *aaa;
|
|
Ipmip_proc_t *proc = ipmip4_diameter_proc(ifp_config->diameter);
|
|
Ipmipha_pktbuf_t *pbuf = IP_NULL;
|
|
Ipmip4_regreq_t *regreq;
|
|
Ip_u32 addr;
|
|
|
|
/**/
|
|
if (ipdiameter_get_avp(hdr, DIAMETER_AVP_CODE_MIP_Reg_Request, &len, &val) != IPCOM_SUCCESS)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to AAA DIAMETER Registration-Request AVP not present. Poorly formed"));
|
|
goto error_out;
|
|
}
|
|
|
|
pbuf = (Ipmipha_pktbuf_t *)ipmip_pktbuf_alloc(&data->ipmip4.ipmip, proc, 0);
|
|
aaa = ipmip_pktbuf_pktaux_data_get(&data->ipmip4.ipmip, &pbuf->ipmip4.ipmip, ipmipha_aaa_diameter_srv.pktaux.pktbuf_data_index, IP_TRUE);
|
|
if(IP_NULL == aaa)
|
|
goto error_out;
|
|
|
|
/* Add the registration request */
|
|
ipmip_buffer_append(&pbuf->ipmip4.ipmip.packet, val, len);
|
|
|
|
/* Retrieve the mandatory information */
|
|
if (ipdiameter_get_avp(hdr, DIAMETER_AVP_CODE_MIP_Feature_Vector, &len, &val) != IPCOM_SUCCESS || len < 4)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to AAA DIAMETER Feature Vector not present. Poorly formed"));
|
|
goto error_out;
|
|
}
|
|
|
|
aaa->feature = IP_GET_HTONL(val);
|
|
|
|
/* Retrieve the mandatory information */
|
|
if (ipdiameter_get_avp(hdr, DIAMETER_AVP_CODE_MIP_Mobile_Node_Address, &len, &val) == IPCOM_SUCCESS && len >= 4)
|
|
pbuf->pktinfo.haBindingResolvedHomeAddress = IP_GET_32ON8((val + 2));
|
|
|
|
/* Retrieve the mandatory information */
|
|
if (ipdiameter_get_avp(hdr, DIAMETER_AVP_CODE_MIP_Home_Agent_Address, &len, &val) == IPCOM_SUCCESS && len >= 4)
|
|
pbuf->pktinfo.haBindingResolvedHomeAgentAddress = IP_GET_32ON8((val + 2));
|
|
|
|
/* Retrieve the mandatory information */
|
|
if (ipdiameter_get_avp(hdr, DIAMETER_AVP_CODE_Origin_Host, &len, &val) != IPCOM_SUCCESS)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to AAA DIAMETER Origin-Host AVP not present. Poorly formed"));
|
|
goto error_out;
|
|
}
|
|
|
|
ipmip_util_dup(&aaa->origin_host, val, len);
|
|
aaa->origin_host_length = len;
|
|
|
|
/* Store some values */
|
|
aaa->e2e_id = IP_GET_32ON8(&hdr->e2e_id);
|
|
aaa->hbh_id = IP_GET_32ON8(&hdr->hbh_id);
|
|
|
|
/* Retrieve the mandatory information */
|
|
if (ipdiameter_get_avp(hdr, DIAMETER_AVP_CODE_Session_Id, &len, &val) != IPCOM_SUCCESS)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to AAA DIAMETER Session-ID AVP not present. Poorly formed"));
|
|
goto error_out;
|
|
}
|
|
|
|
ipmip_util_dup(&aaa->session_id, val, len);
|
|
aaa->session_id_length = len;
|
|
aaa->peer = peer;
|
|
|
|
/**/
|
|
regreq = IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet);
|
|
addr = IP_GET_32ON8(®req->home_agent);
|
|
|
|
/**/
|
|
if (addr == 0 || addr == 0xffffffff)
|
|
addr = pbuf->pktinfo.haBindingResolvedHomeAgentAddress;
|
|
|
|
if (addr == 0)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to AAA DIAMETER home agent not properly specified"));
|
|
goto error_out;
|
|
}
|
|
|
|
/* Try locate the interface */
|
|
pbuf->iff.pub = ipmip4_if_findbyaddr(&data->conf->if_head, addr);
|
|
if ((IP_NULL == pbuf->iff.pub) || (pbuf->iff.priv == IP_NULL))
|
|
{
|
|
/* Failure */
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to AAA DIAMETER home agent %s unknown", ipmip_ntop_inet(proc, addr)));
|
|
goto error_out;
|
|
}
|
|
else
|
|
{
|
|
/* Create a workable pktinfo */
|
|
struct Ip_in_pktinfo pktinfo;
|
|
struct Ip_sockaddr_in src;
|
|
|
|
pktinfo.ipi_addr.s_addr = addr;
|
|
pktinfo.ipi_ifindex = pbuf->iff.pub->ipmip.ifindex;
|
|
|
|
ipmip_pktbuf_srcinfo_dst_inet(&pbuf->ipmip4.ipmip, &pktinfo);
|
|
|
|
ipcom_memset(&src, 0, sizeof(src));
|
|
|
|
addr = IP_GET_32ON8(®req->care_of_addr);
|
|
|
|
src.sin_addr.s_addr = addr;
|
|
src.sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(&src, sizeof(src));
|
|
src.sin_port = ip_htons(IPMIP4_PORT);
|
|
|
|
ipmip_util_dup(&pbuf->ipmip4.ipmip.srcinfo.src, &src, sizeof(src));
|
|
}
|
|
|
|
/* Retrieve the first byte */
|
|
pbuf->pktinfo.haBindingRegType = *(Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet);
|
|
pbuf->haBindingTimeStamp = ipmip_util_time();
|
|
|
|
/* Mark the security policies as fullfilled */
|
|
pbuf->pktinfo.haBindingForeignHomeSAPolicyOK = IP_TRUE;
|
|
pbuf->pktinfo.haBindingMobileHomeSAPolicyOK = IP_TRUE;
|
|
pbuf->reply_transport = &ipmipha_aaa_diameter_srv;
|
|
|
|
if (!ipmipha_reg_input_parse_request(data, proc, pbuf))
|
|
goto error_out;
|
|
|
|
/* OK; */
|
|
if (IP_BIT_ISTRUE(aaa->feature, IPMIP4_DIAMETER_FEATURE_MN_HA_KEYREQ))
|
|
{
|
|
ipmipha_aaa_diameter_parse_mn_ha_keyreq(data, proc, aaa, pbuf, hdr);
|
|
if (pbuf->ipmip4.ipmip.message != IP_NULL)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to %s", pbuf->ipmip4.ipmip.message));
|
|
goto error_out;
|
|
}
|
|
}
|
|
|
|
/* OK; */
|
|
if (IP_BIT_ISTRUE(aaa->feature, IPMIP4_DIAMETER_FEATURE_MN_FA_KEYREQ))
|
|
{
|
|
ipmipha_aaa_diameter_parse_mn_fa_keyreq(data, proc, aaa, pbuf, hdr);
|
|
if (pbuf->ipmip4.ipmip.message != IP_NULL)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to %s", pbuf->ipmip4.ipmip.message));
|
|
goto error_out;
|
|
}
|
|
}
|
|
|
|
/* OK; */
|
|
if (IP_BIT_ISTRUE(aaa->feature, IPMIP4_DIAMETER_FEATURE_FA_HA_KEYREQ))
|
|
{
|
|
ipmipha_aaa_diameter_parse_fa_ha_keyreq(data, proc, aaa, pbuf, hdr);
|
|
if (pbuf->ipmip4.ipmip.message != IP_NULL)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"Registration request silently discarded due to %s", pbuf->ipmip4.ipmip.message));
|
|
goto error_out;
|
|
}
|
|
}
|
|
|
|
if (pbuf->ipmip4.ext.mobile.mn_aaa != IP_NULL)
|
|
pbuf->pktinfo.haBindingSPIMobileAAA = IP_GET_NTOHL(&((Ipmip4_ext_gen_auth_t *)pbuf->ipmip4.ext.mobile.mn_aaa)->spi[0]);
|
|
|
|
/* Update pending information */
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->ipmip4.ipmip,
|
|
proc,
|
|
"DIAMETER Registration Request received with id=0x%08x",
|
|
pbuf->pktinfo.haBindingRegIDLow));
|
|
|
|
/* Try locate the mobile node */
|
|
ipmipha_node_lookup(data,
|
|
proc,
|
|
pbuf->iff.priv,
|
|
pbuf->pktinfo.haBindingHomeAddress,
|
|
&pbuf->ipmip4.ipmip.timeout,
|
|
(Ipmip_timer_func_t)ipmipha_reg_request_process,
|
|
pbuf);
|
|
|
|
return;
|
|
|
|
error_out:
|
|
/* Need to deal with a failed request */
|
|
/* Send a HAR error */
|
|
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
|
|
}
|
|
}
|
|
|
|
|
|
IP_STATIC void
|
|
ipmipha_aaa_diameter_config_ifp(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
struct Ipmipha_iff *ifp,
|
|
void *gcfg,
|
|
Ipmipha_aaa_diameter_config_ifp_t *cfg,
|
|
Ipmip_cli_message_t *request)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(gcfg);
|
|
IPMIP_UNUSED_PARAMETER(request);
|
|
|
|
if (action == IPMIP_CALLBACK_CONFIG_READ)
|
|
{
|
|
if (ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipha.aaa.diameter.enable"), "ipmipha.if.%s.aaa.diameter.enable", ifp->iff.ipmip.ifname))
|
|
{
|
|
cfg->diameter = ipmip4_diameter_context_create(&ctx->ipmip4, proc, "ipmipha.aaa.diameter", "ipmipha.if.%s.aaa.diametr", ifp->iff.ipmip.ifname);
|
|
cfg->access = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipha.aaa.diameter.access"), "ipmipha.if.%s.aaa.diameter.access", ifp->iff.ipmip.ifname);
|
|
cfg->access_require = ipmip_sysvar_bool(ipmip_sysvar_bool(IP_FALSE, "ipmipha.aaa.diameter.access.required"), "ipmipha.if.%s.aaa.diameter.access.required", ifp->iff.ipmip.ifname);
|
|
cfg->access_timeout = ipmip_sysvar_ulong(ipmip_sysvar_ulong(0, "ipmipha.aaa.diameter.access.time_interval"), "ipmipha.if.%s.aaa.diameter.access.time_interval", ifp->iff.ipmip.ifname);
|
|
cfg->data = ctx;
|
|
|
|
ipmip4_diameter_HAR_callback(cfg, (Ipmip4_diameter_HAR_recv_t)ipmipha_aaa_diameter_HAR_recv);
|
|
}
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_FREE)
|
|
{
|
|
if (cfg->diameter)
|
|
{
|
|
ipmip4_diameter_HAR_callback(IP_NULL, (Ipmip4_diameter_HAR_recv_t)IP_NULL);
|
|
ipmip4_diameter_context_destroy(&ctx->ipmip4, proc, cfg->diameter);
|
|
}
|
|
cfg->diameter = IP_NULL;
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_DUMP)
|
|
{
|
|
if (cfg->diameter)
|
|
{
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.diameter.enable=enabled",
|
|
ifp->iff.ipmip.ifname);
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.diameter.access=%s",
|
|
ifp->iff.ipmip.ifname, cfg->access? "enabled" : "disabled");
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.diameter.access.required=%s",
|
|
ifp->iff.ipmip.ifname, cfg->access_require? "enabled" : "disabled");
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.diameter.access.time_interval=%d",
|
|
ifp->iff.ipmip.ifname, cfg->access_timeout);
|
|
ipmip4_diameter_context_dump(&ctx->ipmip4, proc, cfg->diameter, request, "ipmipha.if.%s.aaa.diameter", ifp->iff.ipmip.ifname);
|
|
}
|
|
else
|
|
{
|
|
ipmip_cli_config_printf(&request->message,
|
|
"ipmipha.if.%s.aaa.diameter.enable=disabled",
|
|
ifp->iff.ipmip.ifname);
|
|
}
|
|
}
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipha_aaa_diameter_setup(struct Ipmipha_data *ctx,
|
|
struct Ipmip_proc *proc,
|
|
int action,
|
|
void *global_config,
|
|
Ipmipha_aaa_diameter_config_ifp_t *ifp_config,
|
|
void *node_config,
|
|
struct Ipmipha_node *node,
|
|
Ipmip_cli_message_t *request)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(global_config);
|
|
IPMIP_UNUSED_PARAMETER(node_config);
|
|
IPMIP_UNUSED_PARAMETER(node);
|
|
IPMIP_UNUSED_PARAMETER(request);
|
|
|
|
if (action == IPMIP_CALLBACK_CONFIG_READ)
|
|
{
|
|
return ifp_config->diameter != IP_NULL;
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_FREE)
|
|
{
|
|
/* No dyncamically allocated values */
|
|
}
|
|
else if (action == IPMIP_CALLBACK_CONFIG_DUMP)
|
|
{
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
IP_GLOBAL void ipmipha_aaa_diameter_install(void);
|
|
IP_GLOBAL void
|
|
ipmipha_aaa_diameter_install(void)
|
|
{
|
|
ipcom_memset(&ipmipha_aaa_diameter_srv, 0, sizeof(ipmipha_aaa_diameter_srv));
|
|
|
|
ipmipha_aaa_diameter_srv.name = IPMIPHA_AAA_DIAMETER;
|
|
ipmipha_aaa_diameter_srv.ifp_data_size = sizeof(Ipmipha_aaa_diameter_config_ifp_t);
|
|
ipmipha_aaa_diameter_srv.config_ifp = (Ipmipha_extension_config_ifp_t)ipmipha_aaa_diameter_config_ifp;
|
|
|
|
ipmipha_aaa_diameter_srv.pkt_req_validate = (Ipmipha_extension_pkt_req_validate_t)ipmipha_aaa_diameter_pkt_req_verify;
|
|
ipmipha_aaa_diameter_srv.pkt_rep_transport = (Ipmipha_extension_pkt_rep_transport_t)ipmipha_aaa_diameter_HAA;
|
|
ipmipha_aaa_diameter_srv.pkt_rep_mobile_home = (Ipmipha_extension_pkt_req_mobile_home_t)ipmipha_aaa_diameter_pkt_rep_mobile_home;
|
|
|
|
ipmipha_aaa_diameter_srv.setup = (Ipmipha_extension_setup_t)ipmipha_aaa_diameter_setup;
|
|
|
|
/**/
|
|
ipmipha_aaa_diameter_srv.pktaux.pktbuf_data_size = sizeof(Ipmipha_aaa_diameter_pktbuf_data_t);
|
|
ipmipha_aaa_diameter_srv.pktaux.pktbuf_data_free = (Ipmip_pktbuf_free_data_t)ipmipha_aaa_diameter_pktaux_free;
|
|
|
|
ipmipha_context_register_extension(&ipmipha_aaa_diameter_srv, IPMIPHA_FUNCTION_AAA);
|
|
}
|
|
|
|
#else
|
|
IP_GLOBAL void ipmipha_aaa_diameter_install(void);
|
|
IP_GLOBAL void
|
|
ipmipha_aaa_diameter_install(void)
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
#endif
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|