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

2600 lines
134 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipha_reg.c,v $ $Revision: 1.26.10.2 $
* $Source: /home/interpeak/CVSRoot/ipmipha/src/ipmipha_reg.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
****************************************************************************
*/
#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_util.h>
#include "ipmipha.h"
#include "ipmip4_mib.h"
#include "ipmipha_h.h"
#include "ipmipha_attr_h.h"
#include "ipmipha_reg.h"
#include "ipmipha_if.h"
#include "ipmipha_node.h"
#include "ipmipha_agent.h"
#include "ipmipha_pktbuf.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmipha_reg_revoke_ack
*===========================================================================
* Description: Send a revocation request for this particular binding
* Parameters: data - Data
* proc - Process
* node - Node
* binding - Binding
* pbuf - Packet buffer
* Returns:
*
*/
IP_STATIC void
ipmipha_reg_revoke_ack(struct Ipmipha_data *data,
struct Ipmip_proc *proc,
struct Ipmipha_node *node,
struct Ipmipha_node_binding *binding,
struct Ipmipha_pktbuf *pbuf)
{
/**/
Ipmip4_regrevack_t regrev;
IPMIP_UNUSED_PARAMETER(node);
ipcom_memset(&regrev, 0, sizeof(regrev));
if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL)
goto error_out;
regrev.type = IPMIP4_TYPE_REG_REGREVACK;
regrev.home_address = pbuf->pktinfo.haBindingHomeAddress;
regrev.identifier = ip_htonl(pbuf->pktinfo.haBindingRevocationTimeStamp);
/**/
if ((binding == IP_NULL || IP_BIT_ISSET(binding->haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_INFORM)) && IP_BIT_ISTRUE(pbuf->pktinfo.haBindingOptions, IPMIP4_REG_EXT_REGREV_FLAG_INFORM))
regrev.flags |= ip_htons(IPMIP4_REG_EXT_REGREV_FLAG_INFORM);
/* Reset the buffer */
ipmip_buffer_shrink(&pbuf->ipmip4.ipmip.packet, 0);
/* Add the header */
ipmip_buffer_append(&pbuf->ipmip4.ipmip.packet, &regrev, sizeof(regrev));
/* Add the foreign to home authentication */
if (ipmip4_auth_append_foreign_to_home(&pbuf->ipmip4.ipmip.packet, pbuf->pktinfo.haBindingSPIForeignHome) == IP_FALSE)
goto error_out;
/* Send packet using UDP socket */
if (ipmip4_pkt_udp_sendmsg(&data->ipmip4,
proc,
&pbuf->ipmip4.ipmip.packet,
pbuf->iff.pub->ifaddr,
data->ipmip4.pkt->s_udp_out.sin_port,
pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr,
pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port,
IP_NULL) == IP_FALSE)
{
/**/
}
error_out:
/* Remove the reference */
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
}
/*
*===========================================================================
* ipmipha_reg_tunnel_type
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_u8
ipmipha_reg_tunnel_type(Ipmipha_pktbuf_t *pbuf)
{
if (IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_MINIMAL_ENC))
return IPMIP_TUNNELTYPE_MINENC;
else if (IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_GRE_ENC))
return IPMIP_TUNNELTYPE_GRE;
return IPMIP_TUNNELTYPE_IPIP;
}
/*
*===========================================================================
* ipmipha_reg_spi_lookup_home_sa
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipmip4_auth_spi_t *
ipmipha_reg_spi_lookup_home_sa(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf)
{
int i;
Ipmip4_auth_spi_t *spi = IP_NULL;
IPMIP_UNUSED_PARAMETER(data);
IPMIP_UNUSED_PARAMETER(proc);
for (i = 0; pbuf->iff.priv->security.spi_mn_lookup_order[i] != IPMIPHA_SPI_MN_NONE; i++)
{
switch (pbuf->iff.priv->security.spi_mn_lookup_order[i])
{
case IPMIPHA_SPI_MN_HOA:
if (pbuf->pktinfo.haBindingHomeAddress != 0)
spi = ipmip4_auth_spi_table_get(pbuf->iff.priv->security.spi_mn, pbuf->pktinfo.haBindingHomeAddress);
break;
case IPMIPHA_SPI_MN_NAI:
if (pbuf->ipmip4.ext.mobile.nai_mobile)
spi = ipmip4_auth_spi_hash_get(pbuf->iff.priv->security.spi_nai,
(char *)IPMIP4_MSGEXT_SHDR_EXT_DATA(pbuf->ipmip4.ext.mobile.nai_mobile),
IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->ipmip4.ext.mobile.nai_mobile));
break;
}
if (spi)
return spi;
}
return 0;
}
/*
*===========================================================================
* ipmipha_reg_spi_lookup_home_sa
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ipmip4_auth_spi_t *
ipmipha_reg_spi_lookup_foreign_sa(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf)
{
IPMIP_UNUSED_PARAMETER(data);
IPMIP_UNUSED_PARAMETER(proc);
if (pbuf->pktinfo.haBindingCOA != 0)
return ipmip4_auth_spi_table_get(pbuf->iff.priv->security.spi_fa, pbuf->pktinfo.haBindingCOA);
return IP_NULL;
}
/*
*===========================================================================
* ipmipha_reg_reply
*===========================================================================
* Description: Send a reply based on the parameters in the packet buffer.
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipmipha_reg_reply(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_node_t *node,
Ipmipha_pktbuf_t *pbuf)
{
/**/
Ipmipha_pktbuf_t *rpbuf = (Ipmipha_pktbuf_t *)ipmip_pktbuf_alloc(&data->ipmip4.ipmip, proc, 512);
Ipmip4_regrep_t reply;
reply.type = IPMIP4_TYPE_REG_REPLY;
reply.code = pbuf->pktinfo.haBindingHAErrorCode;
reply.lifetime = ip_htons(pbuf->pktinfo.haBindingTimeGranted);
reply.home_addr = pbuf->pktinfo.haBindingHomeAddress;
reply.home_agent = pbuf->iff.pub->ifaddr;
reply.id[0] = ip_htonl( ((Ip_u32)pbuf->haBindingTimeStamp) + IPMIP4_JAN_1970);
reply.id[1] = pbuf->pktinfo.haBindingRegIDLow;
/* Add the header */
ipmip_buffer_append(&rpbuf->ipmip4.ipmip.packet, &reply, sizeof(reply));
/* Add the home agent's NAI, if applicable */
if (pbuf->iff.priv->nai_ha)
ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, pbuf->iff.priv->nai_ha);
/* If there's a mobile NAI; add it */
if (pbuf->ipmip4.ext.mobile.nai_mobile)
ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, pbuf->ipmip4.ext.mobile.nai_mobile);
/* We're DHAAD redirecting */
if (pbuf->pktinfo.haBindingHAErrorCode == IPMIP4_CODE_REP_HA_REGISTER_REDIRECTED)
{
Ip_u8 redir[8];
redir[0] = IPMIP4_EXT_TYPE_DYNAMIC_HA;
redir[1] = IPMIP4_DYNAMIC_HA_SUBTYPE_REDIRECTED;
IP_SET_HTONS(&redir[2], 4);
IP_SET_32ON8(&redir[4], pbuf->pktinfo.haBindingHomeAgentAddress);
ipmip4_msgext_buffer_append_lhdr(&rpbuf->ipmip4.ipmip.packet, (void *)redir);
}
/* Do we have a mobile node UDP tunneling request */
if (pbuf->pktinfo.haBindingHAErrorCode < 2)
ipmip_buffer_append(&rpbuf->ipmip4.ipmip.packet, IPMIP_BUFFER_DATA(&pbuf->reply_mn), IPMIP_BUFFER_SIZE(&pbuf->reply_mn));
/* Do we have a selected AAAH home server? */
if (node != IP_NULL)
{
if (node->nai_aaah != IP_NULL)
ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, node->nai_aaah);
}
/* Add any mobile node specific external extensions */
ipmipha_node_function_rep_mobile_home(data, proc, node, pbuf, rpbuf);
/* Try append mobile to home; if set */
if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL)
{
Ipmip4_auth_spi_t *spi = IP_NULL;
/**/
if (pbuf->ipmip4.ext.mobile.mobile_home)
{
Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.mobile_home;
spi = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi));
}
if (pbuf->iff.priv->security.spi_mn_lookup_required || (pbuf->pktinfo.haBindingSPIMobileHome = spi) == IP_NULL)
pbuf->pktinfo.haBindingSPIMobileHome = ipmipha_reg_spi_lookup_home_sa(data, proc, pbuf);
if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Failed locating mobile-home extension SPI for RegReply (%d) to %s:%d",
pbuf->pktinfo.haBindingHAErrorCode,
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src),
ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port)));
goto error_out;
}
}
if (!ipmip4_auth_append_mobile_to_home(&rpbuf->ipmip4.ipmip.packet, pbuf->pktinfo.haBindingSPIMobileHome))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Failed adding mobile-home extension to RegReply (%d) to %s:%d",
pbuf->pktinfo.haBindingHAErrorCode,
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src),
ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port)));
goto error_out;
}
/* Time to add any HA <-> FA */
if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION))
{
/* Do we have a mobile node UDP tunneling request */
if (pbuf->pktinfo.haBindingHAErrorCode < 2)
ipmip_buffer_append(&rpbuf->ipmip4.ipmip.packet, IPMIP_BUFFER_DATA(&pbuf->reply_fa), IPMIP_BUFFER_SIZE(&pbuf->reply_fa));
/* Add any challenges */
if (pbuf->ipmip4.ext.mobile.challenge != IP_NULL)
ipmip4_msgext_buffer_append_shdr(&rpbuf->ipmip4.ipmip.packet, (void *)pbuf->ipmip4.ext.mobile.challenge);
/* Add any mobile node specific external extensions */
ipmipha_node_function_rep_mobile_foreign(data, proc, node, pbuf, rpbuf);
if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL)
pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_table_get(pbuf->iff.priv->security.spi_fa, pbuf->pktinfo.haBindingCOA);
if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL && pbuf->ipmip4.ext.mobile.foreign_home != IP_NULL)
{
Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home;
pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi));
}
if (pbuf->pktinfo.haBindingSPIForeignHome != IP_NULL)
{
if (!ipmip4_auth_append_foreign_to_home(&rpbuf->ipmip4.ipmip.packet, pbuf->pktinfo.haBindingSPIForeignHome))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Failed adding foreign-home extension to RegReply (%d) to %s:%d",
pbuf->pktinfo.haBindingHAErrorCode,
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src),
ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port)));
goto error_out;
}
}
}
/**/
if (pbuf->reply_transport != IP_NULL)
(*pbuf->reply_transport->pkt_rep_transport) (data, proc, data->conf->extdata[pbuf->reply_transport->func][pbuf->reply_transport->type], pbuf->iff.priv->extdata[pbuf->reply_transport->func][pbuf->reply_transport->type], node->extdata[pbuf->reply_transport->func][pbuf->reply_transport->type], node, pbuf, rpbuf);
else
{
/* Send packet using UDP socket */
if (ipmip4_pkt_udp_sendmsg(&data->ipmip4,
proc,
&rpbuf->ipmip4.ipmip.packet,
pbuf->iff.pub->ifaddr,
data->ipmip4.pkt->s_udp_out.sin_port,
pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr,
pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port,
IP_NULL) == IP_FALSE)
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haReasonUnspecified, 1);
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Failed Sending RegReply (%d) to %s:%d",
pbuf->pktinfo.haBindingHAErrorCode,
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src),
ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port)));
}
else
{
if (pbuf->pktinfo.haBindingTimeGranted == 0)
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haDeRegRepliesSent, 1);
}
else
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRepliesSent, 1);
}
IPMIP4_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Sending RegReply id=0x%08x (%d) to %s:%d",
pbuf->pktinfo.haBindingRegIDLow,
pbuf->pktinfo.haBindingHAErrorCode,
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src),
ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port)));
}
}
error_out:
/* Remove the reference */
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &rpbuf->ipmip4.ipmip);
}
/*
*===========================================================================
* ipmipha_reg_request_error
*===========================================================================
* Description: Error stage
* Parameters: pbuf - The packet buffer
* req - Type of major request
* Returns:
*
*/
IP_STATIC int
ipmipha_reg_request_error(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf,
Ip_u8 code)
{
if (code != 0)
{
pbuf->ipmip4.ipmip.error_code = code;
pbuf->pktinfo.haBindingHAErrorCode = pbuf->ipmip4.ipmip.error_code;
switch (pbuf->ipmip4.ipmip.error_code)
{
case IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haPoorlyFormedRequest, 1);
break;
case IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haAdmProhibited, 1);
break;
case IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haInsufficientResource, 1);
break;
case IPMIP4_CODE_REP_HA_MN_FAILED_AUTH:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haMNAuthenticationFailure, 1);
break;
case IPMIP4_CODE_REP_HA_FA_FAILED_AUTH:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haFAAuthenticationFailure, 1);
break;
case IPMIP4_CODE_REP_HA_REG_ID_MISMATCH:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haIDMismatch, 1);
break;
case IPMIP4_CODE_REP_HA_UNKNOWN_HOME_AGENT_ADDR:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haUnknownHA, 1);
break;
case IPMIP4_CODE_REP_HA_TOO_MANY_SIM:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haTooManyBindings, 1);
break;
default:
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haReasonUnspecified, 1);
break;
}
/* Reg reply consumes the buffer */
ipmipha_reg_reply(data, proc, (Ipmipha_node_t *)pbuf->node, pbuf);
}
else
{
/* Free it */
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
}
return IPMIP_TIMER_RET_DONE;
}
/*
*===========================================================================
* ipmipha_reg_verify_keygen
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_bool
ipmipha_reg_verify_keygen(Ipmip4_auth_spi_t *spi,
Ipmip4_ext_auth_t *auth)
{
/* No generated SPI */
/* No auth; we do have a generated SPI. Auth must be set */
if (auth == IP_NULL)
return IP_FALSE;
/* Does the SPI match? */
return IP_GET_HTONL(auth->spi) == spi->spi;
}
/*
*===========================================================================
* ipmipha_reg_input_request
*===========================================================================
* Description: Handles registration request packages.
* Either forwards a request from mn -> ha,
* or replies to mn cause of mn's bad request.
* Parameters: pbuf - Packet buffer
* Returns:
*
*/
IP_STATIC void
ipmipha_reg_input_request(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf)
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1);
if (!ipmipha_reg_input_parse_request(data, proc, pbuf))
return;
if (pbuf->pktinfo.haBindingTimeGranted == 0)
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haDeRegRequestsReceived, 1);
}
else
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1);
}
/* Update pending information */
IPMIP4_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Received RegReq id=0x%08x lifetime=%u CoA=%s from %s:%d",
pbuf->pktinfo.haBindingRegIDLow,
pbuf->pktinfo.haBindingTimeGranted,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src),
ip_ntohs(pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_port)));
/* 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;
}
enum
{
IPMIPHA_REG_REGREVACK_INIT,
IPMIPHA_REG_REGREVACK_VERIFY
};
/*
*===========================================================================
* ipmipha_reg_ret_process
*===========================================================================
* Description: Process a container stage
* Parameters: pbuf - The packet buffer
* req - Type of major request
* Returns: IP_FALSE
*
*/
IP_STATIC int
ipmipha_reg_regrevack_process(int event,
Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf,
Ipmipha_node_t *node)
{
if (event == IPMIP_TIMER_EVENT_RUN)
{
Ipmipha_node_binding_t *binding = IP_NULL;
if (node == IP_NULL)
node = (Ipmipha_node_t *)pbuf->node;
if (node == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to unknown node specified in registration revocation ack",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
switch (pbuf->pktinfo.haBindingParsingState)
{
case IPMIPHA_REG_REGREVACK_INIT:
pbuf->node = node;
{
Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home;
Ipmip4_auth_spi_t *spi_fa;
/* Verify the SPI we should use for foreign agent */
spi_fa = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi));
if (spi_fa == IP_NULL)
{
/* Unknown security association */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to foreign agent requested a non-existant security association",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
if (pbuf->iff.priv->security.spi_fa_lookup_required)
{
Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_foreign_sa(data, proc, pbuf);
if (spi == IP_NULL)
{
/* Unknown security association */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to foreign agent lacks configured security association with this home agent",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
else if(spi->spi != spi_fa->spi)
{
/* Go use the configured value */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to foreign agent used an invalid security association SPI %d, configured to use %d",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
spi_fa->spi,
spi->spi));
goto done_out;
}
}
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REGREVACK_VERIFY;
if (ipmip4_auth_verify(&data->ipmip4,
proc,
&pbuf->ipmip4,
pbuf->ipmip4.ext.mobile.foreign_home,
spi_fa,
node->lock,
(Ipmip_timer_func_t)ipmipha_reg_regrevack_process))
return IPMIP_TIMER_RET_PENDING;
}
/* this is an intentional fall through to the next case */
case IPMIPHA_REG_REGREVACK_VERIFY:
if (pbuf->ipmip4.ipmip.message != 0)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to %s",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->ipmip4.ipmip.message));
goto done_out;
}
binding = ipmipha_node_binding_revoked(data, proc, node, pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr, pbuf->pktinfo.haBindingRevocationTimeStamp);
if (binding == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to unknown binding requested in registration revocation ack",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
ipmipha_node_binding_revoked_complete(data, proc, node, binding);
IPMIP4_EVENT_IF(INFO, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request successful",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
}
}
done_out:
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
return IPMIP_TIMER_RET_DONE;
}
/*
*===========================================================================
* ipmipha_reg_input_regrevack
*===========================================================================
* Description: Handles registration request packages.
* Either forwards a request from mn -> ha,
* or replies to mn cause of mn's bad request.
* Parameters: pbuf - Packet buffer
* Returns:
*
*/
IP_STATIC void
ipmipha_reg_input_regrevack(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf)
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1);
/* Check length */
if (IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet) < IPMIP4_REGREVACK_LENGTH)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Truncated registration revocation ack [%d]", IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet)));
goto done_out;
}
else
{
/* Pointers to the packet */
Ipmip4_regrevack_t *regrev = IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet);
/* Store pending reg information */
pbuf->pktinfo.haBindingRevocationTimeStamp = IP_GET_HTONL(&regrev->identifier);
pbuf->pktinfo.haBindingOptions = IP_GET_HTONS(&regrev->flags);
pbuf->pktinfo.haBindingHomeAddress = IP_GET_32ON8(&regrev->home_address);
}
/* OK */
pbuf->ipmip4.ext.mobile.result = ipmip4_msgext_mobile_parse_ext(&data->ipmip4, proc, &pbuf->ipmip4, IPMIP4_REGREVACK_LENGTH);
/* Parse extensions */
switch (pbuf->ipmip4.ext.mobile.result)
{
case IPMIP4_REG_EXT_UNKNOWN_VSE:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to bad or unknown VSE",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
case IPMIP4_REG_EXT_FAILED_AUTH:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to bad or duplicate authentication extensions",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
case IPMIP4_REG_EXT_POORLY_FORMED:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to poorly formed request",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
case IPMIP4_REG_EXT_DISCARD:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
/* Do we have a foreign-home authentication? */
if (pbuf->ipmip4.ext.mobile.foreign_home == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation ack silently discarded due to no foreign-home extension in revocation acknowledgement",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
/* 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_regrevack_process,
pbuf);
return;
done_out:
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
}
enum
{
IPMIPHA_REG_REGREVREQ_INIT,
IPMIPHA_REG_REGREVREQ_VERIFY
};
/*
*===========================================================================
* ipmipha_reg_ret_process
*===========================================================================
* Description: Process a container stage
* Parameters: pbuf - The packet buffer
* req - Type of major request
* Returns: IP_FALSE
*
*/
IP_STATIC int
ipmipha_reg_regrevreq_process(int event,
Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf,
Ipmipha_node_t *node)
{
if (event == IPMIP_TIMER_EVENT_RUN)
{
Ipmipha_node_binding_t *binding = IP_NULL;
if (node == IP_NULL)
node = (Ipmipha_node_t *)pbuf->node;
binding = (Ipmipha_node_binding_t *)pbuf->binding;
switch (pbuf->pktinfo.haBindingParsingState)
{
case IPMIPHA_REG_REGREVREQ_INIT:
{
Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home;
/* Verify the SPI we should use for foreign agent */
pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi));
if (node == IP_NULL)
{
ipmipha_reg_revoke_ack(data, proc, IP_NULL, IP_NULL, pbuf);
return IPMIP_TIMER_RET_DONE;
}
pbuf->node = node;
binding = ipmipha_node_binding_coa(data, proc, node, pbuf->pktinfo.haBindingCOA);
if (binding == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to unknown binding requested in registration revocation ack",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
pbuf->binding = binding;
/* Found node & binding */
if (binding->haBindingForeignSA != IP_NULL)
{
pbuf->pktinfo.haBindingSPIForeignHome = binding->haBindingForeignSA;
if (pbuf->pktinfo.haBindingSPIForeignHome->spi != IP_GET_HTONL(auth->spi))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to foreign agent used a security association that does not match AAA generated",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
}
else
{
if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to foreign agent requested a non-existant security association",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
if (pbuf->iff.priv->security.spi_fa_lookup_required)
{
Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_foreign_sa(data, proc, pbuf);
if (spi == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to foreign agent lacks configured security association with this home agent",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
else if(spi->spi != pbuf->pktinfo.haBindingSPIForeignHome->spi)
{
/* Go use the configured value */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to foreign agent used an invalid security association SPI %d, configured to use %d",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->pktinfo.haBindingSPIForeignHome->spi,
spi->spi));
goto done_out;
}
}
}
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REGREVREQ_VERIFY;
if (ipmip4_auth_verify(&data->ipmip4,
proc,
&pbuf->ipmip4,
pbuf->ipmip4.ext.mobile.foreign_home,
pbuf->pktinfo.haBindingSPIForeignHome,
node->lock,
(Ipmip_timer_func_t)ipmipha_reg_regrevreq_process))
return IPMIP_TIMER_RET_PENDING;
}
/* this is an intentional fall through to the next case */
case IPMIPHA_REG_REGREVREQ_VERIFY:
if (pbuf->ipmip4.ipmip.message != 0)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to %s",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->ipmip4.ipmip.message));
goto done_out;
}
if (!IP_BIT_ARESET(binding->haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_CONFIRMED))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to this binding does not accept revocation usage",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
/**/
if (binding->haBindingRevocationTimeStamp >= pbuf->pktinfo.haBindingRevocationTimeStamp)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to bad revocation time stamp",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
/* Time to revoke */
IPMIP4_EVENT_IF(INFO, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request acknowledged",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
ipmipha_reg_revoke_ack(data, proc, node, binding, pbuf);
ipmipha_node_binding_delete(data, proc, node, binding);
}
}
else
{
done_out:
/* Cancelled or aborted */
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
}
return IPMIP_TIMER_RET_DONE;
}
/*
*===========================================================================
* ipmipha_reg_input_regrevreq
*===========================================================================
* Description: Handles registration request packages.
* Either forwards a request from mn -> ha,
* or replies to mn cause of mn's bad request.
* Parameters: pbuf - Packet buffer
* Returns:
*
*/
IP_STATIC void
ipmipha_reg_input_regrevreq(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf)
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegRequestsReceived, 1);
/* Check length */
if (IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet) < IPMIP4_REGREVREQ_LENGTH)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Truncated registration revocation request [%d]", IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet)));
goto done_out;
}
else
{
/* Pointers to the packet */
Ipmip4_regrevreq_t *regrev = IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet);
/* Store pending reg information */
pbuf->pktinfo.haBindingHomeAgentAddress = IP_GET_32ON8(&regrev->home_domain);
pbuf->pktinfo.haBindingRevocationTimeStamp = IP_GET_HTONL(&regrev->identifier);
pbuf->pktinfo.haBindingOptions = IP_GET_HTONS(&regrev->flags);
pbuf->pktinfo.haBindingHomeAddress = IP_GET_32ON8(&regrev->home_address);
pbuf->pktinfo.haBindingCOA = IP_GET_32ON8(&regrev->foreign_domain);
}
/* OK */
pbuf->ipmip4.ext.mobile.result = ipmip4_msgext_mobile_parse_ext(&data->ipmip4, proc, &pbuf->ipmip4, IPMIP4_REGREVREQ_LENGTH);
/* Parse extensions */
switch (pbuf->ipmip4.ext.mobile.result)
{
case IPMIP4_REG_EXT_UNKNOWN_VSE:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to bad or unknown VSE",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
case IPMIP4_REG_EXT_FAILED_AUTH:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to bad or duplicate authentication extensions",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
case IPMIP4_REG_EXT_POORLY_FORMED:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to poorly formed request",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
case IPMIP4_REG_EXT_DISCARD:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
if (IP_BIT_ISTRUE(pbuf->pktinfo.haBindingOptions, IPMIP4_REG_EXT_REGREV_FLAG_AGENT))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to home agent flag set in revocation request",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
/* Do we have a foreign-home authentication? */
if (pbuf->ipmip4.ext.mobile.foreign_home == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration revocation request silently discarded due to no foreign-home extension in revocation request",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
goto done_out;
}
/* 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_regrevreq_process,
pbuf);
return;
done_out:
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmipha_reg_recv
*===========================================================================
* Description: Handles registration request packages.
* Parameters: data - Context
* proc - Current process.
* pbuf - Packet buffer
* Returns:
*
*/
IP_GLOBAL void
ipmipha_reg_recv(struct Ipmipha_data *data,
struct Ipmip_proc *proc,
Ipmipha_pktbuf_t *pbuf,
void *arg)
{
/* Locate the interface */
IPMIP_UNUSED_PARAMETER(arg);
if (data->conf == IP_NULL)
{
/* Failure */
IPMIP4_EVENT_IF(ERR, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"No valid configuration availble, discarding registration request"));
goto error_out;
}
if (pbuf->ipmip4.ipmip.srcinfo.lladdr == IP_NULL)
{
/* Failure */
IPMIP4_EVENT_IF(ERR, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"No MAC found in message, discarding registration request"));
goto error_out;
}
/* Try locate the interface */
pbuf->iff.pub = ipmip4_if_findbypktinfo(&data->conf->if_head, pbuf->ipmip4.ipmip.srcinfo.dst);
if (pbuf->iff.priv == IP_NULL)
{
/* Failure */
IPMIP4_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"No configured interface found in message, discarding registration request"));
goto error_out;
}
/* Retrieve the first byte */
pbuf->pktinfo.haBindingRegType = *(Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet);
pbuf->haBindingTimeStamp = ipmip_util_time();
switch (pbuf->pktinfo.haBindingRegType)
{
case IPMIP4_TYPE_REG_REQUEST:
if (IP_BIT_ISFALSE(data->shutdown, IPMIPHA_SHUTDOWN_REG))
{
ipmipha_reg_input_request(data, proc, pbuf);
return;
}
break;
case IPMIP4_TYPE_REG_REGREVACK:
ipmipha_reg_input_regrevack(data, proc, pbuf);
return;
case IPMIP4_TYPE_REG_REGREVREQ:
ipmipha_reg_input_regrevreq(data, proc, pbuf);
return;
case IPMIP4_TYPE_REG_NAT_ENCAP:
IPMIP4_EVENT_IF(ERR, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"NAT Encapsulation registration type %d received on %s from %s [%d]",
pbuf->pktinfo.haBindingRegType,
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src),
((Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet))[1]));
goto error_out;
case IPMIP4_TYPE_REG_REPLY:
case IPMIP4_TYPE_REG_HRQST:
case IPMIP4_TYPE_REG_HRPLY:
default:
IPMIP4_EVENT_IF(ERR, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Unknown registration type %d received on %s from %s, discarding registration message",
pbuf->pktinfo.haBindingRegType,
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_sa(proc, pbuf->ipmip4.ipmip.srcinfo.src)));
goto error_out;
}
error_out:
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
}
/*
*===========================================================================
* ipmipha_reg_revoke_request
*===========================================================================
* Description: Send a revocation request for this particular binding
* Parameters: data - Data
* proc - Process
* node - Node
* binding - Binding
* Returns:
*
*/
IP_GLOBAL Ip_bool
ipmipha_reg_revoke_request(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_node_t *node,
Ipmipha_node_binding_t *binding)
{
/**/
Ipmip_buffer_t rbuf;
Ipmip4_regrevreq_t regrev;
ipcom_memset(&regrev, 0, sizeof(regrev));
regrev.type = IPMIP4_TYPE_REG_REGREVREQ;
regrev.home_address = node->haNodeHomeAddress.prefix;
regrev.home_domain = node->ifp->iff.ifaddr;
regrev.foreign_domain = binding->mib.haMobilityBindingCOA.s_addr;
binding->haBindingRevocationTimeStamp = ipmip4_util_now() + 1;
regrev.identifier = ip_htonl(binding->haBindingRevocationTimeStamp);
regrev.flags = ip_htons(IPMIP4_REG_EXT_REGREV_FLAG_AGENT);
if (IP_BIT_ISSET(binding->haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_INFORM))
regrev.flags |= ip_htons(IPMIP4_REG_EXT_REGREV_FLAG_INFORM);
ipmip_buffer_init(&rbuf);
/* Add the header */
ipmip_buffer_append(&rbuf, &regrev, sizeof(regrev));
if (IP_BIT_ISTRUE(binding->mib.haMobilityBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION))
{
if (node->haLastHomeSA == IP_NULL)
goto error_out;
if (!ipmip4_auth_append_mobile_to_home(&rbuf, node->haLastHomeSA))
goto error_out;
}
else
{
if (binding->haLastForeignSA == IP_NULL)
goto error_out;
if (!ipmip4_auth_append_foreign_to_home(&rbuf, binding->haLastForeignSA))
goto error_out;
}
/* Send packet using UDP socket */
if (ipmip4_pkt_udp_sendmsg(&data->ipmip4,
proc,
&rbuf,
node->ifp->iff.ifaddr,
data->ipmip4.pkt->s_udp_out.sin_port,
binding->haBindingTunnelingEndpoint,
binding->haBindingTunnelingPort,
IP_NULL) == IP_TRUE)
{
ipmip_buffer_release(&rbuf);
return IP_TRUE;
}
error_out:
/* Remove the reference */
ipmip_buffer_release(&rbuf);
return IP_FALSE;
}
enum
{
IPMIPHA_REG_REQUEST_INIT,
IPMIPHA_REG_REQUEST_CREATE,
IPMIPHA_REG_REQUEST_PROCESS,
IPMIPHA_REG_REQUEST_AAA,
IPMIPHA_REG_REQUEST_FA_AUTH,
IPMIPHA_REG_REQUEST_HA_AUTH,
IPMIPHA_REG_REQUEST_AUTH_DONE,
IPMIPHA_REG_REQUEST_EXT,
IPMIPHA_REG_REQUEST_PARAMS,
IPMIPHA_REG_REQUEST_HOME_ADDRESS,
IPMIPHA_REG_REQUEST_BINDING_UPDATE,
IPMIPHA_REG_REQUEST_ENABLE
};
/*
*===========================================================================
* ipmipha_reg_request_process
*===========================================================================
* Description: Process a container stage
* Parameters: pbuf - The packet buffer
* req - Type of major request
* Returns: IP_FALSE
*
*/
IP_GLOBAL int
ipmipha_reg_request_process(int event,
Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf,
Ipmipha_node_t *node)
{
if (event == IPMIP_TIMER_EVENT_RUN)
{
Ipmipha_node_binding_t *binding = IP_NULL;
if (node != IP_NULL)
pbuf->node = node;
else
{
/* Restore any stored values */
node = (Ipmipha_node_t *)pbuf->node;
}
/* Always init binding */
binding = (Ipmipha_node_binding_t *)pbuf->binding;
if (node)
ipmip_timer_prepare(&data->ipmip4.ipmip, proc, &node->service, node->lock, (Ipmip_timer_func_t)ipmipha_reg_request_process, pbuf, node);
switch (pbuf->pktinfo.haBindingParsingState)
{
case IPMIPHA_REG_REQUEST_INIT:
if (node == IP_NULL)
{
/* Are we trying to use address allocation? */
if (pbuf->pktinfo.haBindingHomeAddress == 0)
{
/* Check if there's a NAI already matching this particular node */
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_CREATE;
if (ipmipha_node_nai_lookup(data,
proc,
pbuf->iff.priv,
pbuf->ipmip4.ext.mobile.nai_mobile,
&pbuf->ipmip4.ipmip.timeout,
(Ipmip_timer_func_t)ipmipha_reg_request_process,
pbuf))
return IPMIP_TIMER_RET_DONE;
}
}
else
{
/* Flag up the last SA used for mobile home bindings; */
pbuf->pktinfo.haBindingSPIMobileHome = node->haLastHomeSA;
}
/* this is an intentional fall through to the next case */
case IPMIPHA_REG_REQUEST_CREATE:
if (node == IP_NULL)
{
/* Silently discard */
if (IP_BIT_ISSET(data->shutdown, IPMIPHA_SHUTDOWN_NODE))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to agent being paused",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
return ipmipha_reg_request_error(data, proc, pbuf, 0);
}
if (pbuf->pktinfo.haBindingHomeAddress == 0 &&
pbuf->ipmip4.ext.mobile.nai_mobile == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to neither nai nor home address is specified (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST);
}
/* No node found; create one */
node = ipmipha_node_create(data,
proc,
pbuf->iff.priv,
pbuf->pktinfo.haBindingHomeAddress,
pbuf->ipmip4.ext.mobile.nai_mobile);
if (node == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to out of memory allocating node (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES);
}
/* Store the node */
pbuf->node = node;
/* Invoke recursively */
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_PROCESS;
ipmip_timer_call(&data->ipmip4.ipmip, proc, node->lock, (Ipmip_timer_func_t)ipmipha_reg_request_process, pbuf, node);
return IPMIP_TIMER_RET_DONE;
}
/* FALL THROUGH */
case IPMIPHA_REG_REQUEST_PROCESS:
if (pbuf->ipmip4.ipmip.message != 0)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to %s (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->ipmip4.ipmip.message,
pbuf->ipmip4.ipmip.error_code));
return ipmipha_reg_request_error(data, proc, pbuf, pbuf->ipmip4.ipmip.error_code);
}
/* Try find the appropriate binding */
if (binding == IP_NULL)
{
if ((binding = ipmipha_node_binding_coa(data, proc, node, pbuf->pktinfo.haBindingCOA)) != IP_NULL)
pbuf->binding = binding;
}
/* No keyreq's */
if (node->haBindingHomeSA != IP_NULL)
pbuf->pktinfo.haBindingMobileHomeSAPolicyOK = ipmipha_reg_verify_keygen(node->haBindingHomeSA, (Ipmip4_ext_auth_t*)pbuf->ipmip4.ext.mobile.mobile_home);
/* FALL THROUGH */
case IPMIPHA_REG_REQUEST_AAA:
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_AAA;
if (ipmipha_node_function_request_validate(data, proc, node, pbuf, IPMIPHA_FUNCTION_AAA))
return IPMIP_TIMER_RET_PENDING;
if (pbuf->ipmip4.ipmip.message != IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to %s (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->ipmip4.ipmip.message,
IPMIP4_CODE_REP_HA_BAD_AAA_AUTH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_BAD_AAA_AUTH);
}
if (pbuf->haBindingAAAVerified == IP_TRUE)
node->haNodeAAAVerificationTime = pbuf->haBindingTimeStamp;
else if (pbuf->pktinfo.haBindingForeignHomeSAPolicyOK == 0 || pbuf->pktinfo.haBindingMobileHomeSAPolicyOK == 0)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to Insufficient security extensions supplied, and the mn-aaa extension could not be processed (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
return ipmipha_reg_request_error(data, proc, pbuf, 0);
}
/* FALL THROUGH */
case IPMIPHA_REG_REQUEST_HA_AUTH:
/* If there's a security association created due to AAA; indicate it */
if (node->haBindingHomeSA != IP_NULL)
pbuf->pktinfo.haBindingSPIMobileHome = node->haBindingHomeSA;
/* Verify */
if (pbuf->ipmip4.ext.mobile.mobile_home)
{
/**/
Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.mobile_home;
/* We have SPI's assigned to this particular node; these SPI's has been created
* due to AAA, and aren't globally available -- If they exist, the MUST be matched */
if (pbuf->pktinfo.haBindingSPIMobileHome != IP_NULL)
{
/* Use packet buffer's new SA first; fall back on nodes otherwise */
if (pbuf->pktinfo.haBindingSPIMobileHome->spi != IP_GET_HTONL(auth->spi))
{
/* Bad SPI */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to bad SPI %d in mobile-home authentication extension, do not match AAA generated SPI %d (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IP_GET_HTONL(auth->spi),
pbuf->pktinfo.haBindingSPIMobileHome->spi,
IPMIP4_CODE_REP_HA_MN_FAILED_AUTH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH);
}
}
else
{
if (node->haLastHomeSA == IP_NULL || node->haLastHomeSA->spi != IP_GET_HTONL(auth->spi))
{
pbuf->pktinfo.haBindingSPIMobileHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi));
if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to bad SPI in mobile-home authentication extension, do not match any configured security association SPI %d (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IP_GET_HTONL(auth->spi),
IPMIP4_CODE_REP_HA_MN_FAILED_AUTH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH);
}
if (pbuf->iff.priv->security.spi_mn_lookup_required)
{
if (node->haLastHomeSA != IP_NULL)
{
/* Go use the configured value */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to mobile node used an invalid security association SPI %d, configured to use %d (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->pktinfo.haBindingSPIMobileHome->spi,
node->haLastHomeSA->spi,
IPMIP4_CODE_REP_HA_MN_FAILED_AUTH));
pbuf->pktinfo.haBindingSPIMobileHome = node->haLastHomeSA;
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH);
}
else
{
Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_home_sa(data, proc, pbuf);
if (spi == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to mobile node lacks configured security association with this home agent",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
pbuf->pktinfo.haBindingSPIMobileHome = IP_NULL;
return ipmipha_reg_request_error(data, proc, pbuf, 0);
}
else if(spi->spi != pbuf->pktinfo.haBindingSPIMobileHome->spi)
{
/* Go use the configured value */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to mobile node used an invalid security association SPI %d, configured to use %d (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->pktinfo.haBindingSPIMobileHome->spi,
spi->spi,
IPMIP4_CODE_REP_HA_MN_FAILED_AUTH));
pbuf->pktinfo.haBindingSPIMobileHome = spi;
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH);
}
}
}
}
else
{
/* Use the cached SPI */
pbuf->pktinfo.haBindingSPIMobileHome = node->haLastHomeSA;
}
}
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_FA_AUTH;
if (ipmip4_auth_verify(&data->ipmip4,
proc,
&pbuf->ipmip4,
pbuf->ipmip4.ext.mobile.mobile_home,
pbuf->pktinfo.haBindingSPIMobileHome,
node->lock,
(Ipmip_timer_func_t)ipmipha_reg_request_process))
return IPMIP_TIMER_RET_PENDING;
}
else if (pbuf->pktinfo.haBindingSPIMobileHome == IP_NULL)
{
/* Set it to the binding SA */
if ((pbuf->pktinfo.haBindingSPIMobileHome = ipmipha_reg_spi_lookup_home_sa(data, proc, pbuf)) == IP_NULL)
{
/* Unknown security association */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to mobile node lacks security association with home agent",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
return ipmipha_reg_request_error(data, proc, pbuf, 0);
}
}
/* FALL THROUGH */
/* this is an intentional fall through to the next case */
case IPMIPHA_REG_REQUEST_FA_AUTH:
if (pbuf->ipmip4.ipmip.message != IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to %s (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->ipmip4.ipmip.message,
IPMIP4_CODE_REP_HA_FA_FAILED_AUTH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH);
}
/* Verify */
if (pbuf->pktinfo.haBindingTimeGranted != 0)
{
if (pbuf->ipmip4.ext.mobile.foreign_home)
{
Ipmip4_ext_auth_t *auth = (Ipmip4_ext_auth_t *) pbuf->ipmip4.ext.mobile.foreign_home;
/* Verify the SPI we should use for foreign agent */
if (pbuf->haBindingForeignSA != IP_NULL || (binding != IP_NULL && binding->haBindingForeignSA != IP_NULL))
{
pbuf->pktinfo.haBindingSPIForeignHome = pbuf->haBindingForeignSA? pbuf->haBindingForeignSA : binding->haBindingForeignSA;
if(IP_GET_HTONL(auth->spi) != pbuf->pktinfo.haBindingSPIForeignHome->spi)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to foreign agent used an invalid security association SPI %d, should use generated %d (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IP_GET_HTONL(auth->spi),
pbuf->pktinfo.haBindingSPIForeignHome->spi,
IPMIP4_CODE_REP_HA_FA_FAILED_AUTH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH);
}
}
else if (binding == IP_NULL || binding->haLastForeignSA == IP_NULL || binding->haLastForeignSA->spi != IP_GET_HTONL(auth->spi))
{
pbuf->pktinfo.haBindingSPIForeignHome = ipmip4_auth_spi_get(pbuf->iff.priv->security.spi_ctx, IP_GET_HTONL(auth->spi));
if (pbuf->pktinfo.haBindingSPIForeignHome == IP_NULL)
{
/* Unknown security association */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to foreign agent requested a non-existant security association (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_FA_FAILED_AUTH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH);
}
if (pbuf->iff.priv->security.spi_fa_lookup_required)
{
Ipmip4_auth_spi_t *spi = ipmipha_reg_spi_lookup_foreign_sa(data, proc, pbuf);
if (spi == IP_NULL)
{
/* Unknown security association */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to foreign agent lacks configured security association with this home agent (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_FA_FAILED_AUTH));
pbuf->pktinfo.haBindingSPIForeignHome = IP_NULL;
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH);
}
else if(spi->spi != pbuf->pktinfo.haBindingSPIForeignHome->spi)
{
/* Go use the configured value */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to foreign agent used an invalid security association SPI %d, configured to use %d (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->pktinfo.haBindingSPIForeignHome->spi,
spi->spi,
IPMIP4_CODE_REP_HA_FA_FAILED_AUTH));
pbuf->pktinfo.haBindingSPIForeignHome = spi;
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH);
}
}
}
else
{
pbuf->pktinfo.haBindingSPIForeignHome = binding->haLastForeignSA;
}
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_AUTH_DONE;
if (ipmip4_auth_verify(&data->ipmip4,
proc,
&pbuf->ipmip4,
pbuf->ipmip4.ext.mobile.foreign_home,
pbuf->pktinfo.haBindingSPIForeignHome,
node->lock,
(Ipmip_timer_func_t)ipmipha_reg_request_process))
return IPMIP_TIMER_RET_PENDING;
}
else
{
/* Store the SA */
if (pbuf->haBindingForeignSA != IP_NULL || (binding != IP_NULL && binding->haBindingForeignSA != IP_NULL))
pbuf->pktinfo.haBindingSPIForeignHome = pbuf->haBindingForeignSA? pbuf->haBindingForeignSA : binding->haBindingForeignSA;
}
}
/* this is an intentional fall through to the next case */
case IPMIPHA_REG_REQUEST_AUTH_DONE:
if (pbuf->ipmip4.ipmip.message != 0)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to %s (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->ipmip4.ipmip.message,
IPMIP4_CODE_REP_HA_MN_FAILED_AUTH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH);
}
if (pbuf->ipmip4.ext.mobile.nai_mobile == IP_NULL && pbuf->iff.priv->mn_nai_require)
{
/* Go use the configured value */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to mobile node did not provide mobile NAI, and home agent configured to require it (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT);
}
/* Deal with the CVSE; */
switch (pbuf->ipmip4.ext.mobile.result)
{
case IPMIP4_REG_EXT_UNKNOWN_VSE:
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.erronous, pbuf->pktinfo.haBindingAAAAuth))
{
/* Mobile node provided VSE */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to invalid or unsupported CVSE sent by the mobile node (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_ERROR_HA_1));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ERROR_HA_1);
}
else
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to invalid or unsupported CVSE sent by the foreign agent (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_ERROR_HA_2));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ERROR_HA_2);
}
}
if (IP_BIT_ISTRUE(node->state, IPMIPHA_NODE_STATE_HOME_ADDRESS))
pbuf->pktinfo.haBindingResolvedHomeAddress = node->haNodeHomeAddress.prefix;
/* this is an intentional fall through to the next case */
case IPMIPHA_REG_REQUEST_EXT:
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_EXT;
if (ipmipha_node_function_request_validate(data, proc, node, pbuf, IPMIPHA_FUNCTION_REGEXT))
return IPMIP_TIMER_RET_PENDING;
if (node->registrations == 0)
{
if (pbuf->pktinfo.haBindingResolvedHomeAgentAddress)
pbuf->pktinfo.haBindingHomeAgentAddress = pbuf->pktinfo.haBindingResolvedHomeAgentAddress;
}
else
{
/**/
pbuf->pktinfo.haBindingHomeAgentAddress = pbuf->iff.pub->ifaddr;
}
if (pbuf->ipmip4.ipmip.message != 0)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to %s (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
pbuf->ipmip4.ipmip.message,
pbuf->ipmip4.ipmip.error_code));
return ipmipha_reg_request_error(data, proc, pbuf, pbuf->ipmip4.ipmip.error_code);
}
if (pbuf->pktinfo.haBindingHomeAgentAddress != pbuf->iff.pub->ifaddr)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to request not destined for this home agent(discovery?) (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_UNKNOWN_HOME_AGENT_ADDR));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_UNKNOWN_HOME_AGENT_ADDR);
}
/* FALL THROUGH */
case IPMIPHA_REG_REQUEST_PARAMS:
/* Set the agent bit */
if (pbuf->iff.priv->replay_diff != 0)
{
Ip_time_t packet_time = (Ip_time_t) (ip_ntohl(pbuf->pktinfo.haBindingRegIDHigh) - IPMIP4_JAN_1970);
if ((unsigned)(pbuf->haBindingTimeStamp - packet_time) > pbuf->iff.priv->replay_diff)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to replay protection: request time = %s, HA time = %s, diff=%d seconds (allowed=%d) (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
ipmip_ntop_time(proc, packet_time),
ipmip_ntop_time(proc, pbuf->haBindingTimeStamp),
pbuf->haBindingTimeStamp - packet_time,
pbuf->iff.priv->replay_diff,
IPMIP4_CODE_REP_HA_REG_ID_MISMATCH));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_REG_ID_MISMATCH);
}
}
if (pbuf->pktinfo.haBindingTimeGranted != 0)
{
pbuf->pktinfo.haBindingTunnelType = ipmipha_reg_tunnel_type(pbuf);
if (pbuf->iff.priv->tunnel.enabled[pbuf->pktinfo.haBindingTunnelType] == IP_FALSE)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to encapsulation %s unavailable (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
ipmip_util_tunnel_to_name(pbuf->pktinfo.haBindingTunnelType),
IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL);
}
/* Reverse tunneling required but not set */
if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_REVERSE_TUNNELING) &&
pbuf->iff.priv->tunnel.reverse == IPMIP_SYSVAR_MODE_REQUIRED)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to reverse tunneling required - T bit not set (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_REV_TUNNEL_MANDATORY));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_REV_TUNNEL_MANDATORY);
}
/* Reverse tunneling forbidden but set */
else if (IP_BIT_ISTRUE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_REVERSE_TUNNELING) &&
pbuf->iff.priv->tunnel.reverse == IPMIP_SYSVAR_MODE_DISABLED)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to reverse tunneling forbidden - T bit is set (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_REV_TUNNEL_UNAVAIL));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_REV_TUNNEL_UNAVAIL);
}
}
if (pbuf->ipmip4.ext.mobile.revocation != IP_NULL)
{
IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_REQUESTED);
if (pbuf->iff.priv->revocation)
{
Ipmip4_reg_ext_revocation_t *req = (Ipmip4_reg_ext_revocation_t *)pbuf->ipmip4.ext.mobile.revocation;
Ip_u16 flags;
/* Mobile node 'extension', but no 'D' flag set? */
if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION))
{
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.revocation, pbuf->pktinfo.haBindingInnerAuth))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to 'D' flag not set in request, but mobile node appended revocation extension (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST);
}
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.revocation, pbuf->pktinfo.haBindingOuterAuth))
IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_RECEIVED);
}
else
{
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.revocation, pbuf->pktinfo.haBindingInnerAuth))
IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_RECEIVED);
}
if (IP_BIT_ARESET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_REVOCATION_CONFIRMED))
{
Ipmip4_reg_ext_revocation_t rev_rep;
ipcom_memset(&rev_rep, 0, sizeof(rev_rep));
flags = IP_GET_NTOHS(&req->flags);
pbuf->pktinfo.haBindingRevocationInform = IP_BIT_ISTRUE(flags, IPMIP4_REG_EXT_REVOCATION_INFORM);
pbuf->pktinfo.haBindingRevocationTimeStamp = IP_GET_NTOHL(&req->timestamp);
rev_rep.type = IPMIP4_EXT_TYPE_REVOCATION;
rev_rep.length = sizeof(rev_rep) - 2;
rev_rep.timestamp = ipmip4_util_now();
rev_rep.timestamp = ip_htonl(rev_rep.timestamp);
/* */
if (pbuf->pktinfo.haBindingRevocationInform)
rev_rep.flags |= ip_htons(IPMIP4_REG_EXT_REVOCATION_INFORM);
if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION))
ipmip4_msgext_buffer_append_shdr(&pbuf->reply_fa, (void *)&rev_rep);
else
ipmip4_msgext_buffer_append_shdr(&pbuf->reply_mn, (void *)&rev_rep);
}
}
}
if (pbuf->ipmip4.ext.mobile.udp_tunnel_req != IP_NULL)
{
IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_NAT_T_REQUESTED);
/* UDP encapsulation requested */
if (pbuf->iff.priv->nat_t)
{
Ipmip4_reg_ext_udp_tunnel_req_t *req = (Ipmip4_reg_ext_udp_tunnel_req_t *) pbuf->ipmip4.ext.mobile.udp_tunnel_req;
Ip_u8 encap;
encap = ipmip_util_proto_to_tunnel(req->encap);
/**/
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.udp_tunnel_req, pbuf->pktinfo.haBindingInnerAuth))
{
/* Mobile node 'extension', but no 'D' flag set? */
if (IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to 'D' flag not set in request, but mobile node used NAT-T (RFC3519) UDP Tunnel request (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST);
}
/* This registration is done through the FA; co-located forced registration */
if (IP_BIT_ISTRUE(req->flags, IPMIP4_REG_EXT_UDP_FLAG_REGREQ))
{
/* Mark it as a pending NAT-T */
IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_NAT_T_UNRESOLVED);
}
}
else
{
/* Foreign agent 'extension', but co-located flag set? */
if (IP_BIT_ISTRUE(req->flags, IPMIP4_REG_EXT_UDP_FLAG_REGREQ))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to 'R' flag set in NAT-T (RFC3519) UDP Tunnel requests, but extension outside MN-HA authentication (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST);
}
}
pbuf->pktinfo.haBindingTunnelEndpoint = pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr;
{
Ipmip4_reg_ext_udp_tunnel_rep_t rep;
ipcom_memset(&rep, 0, sizeof(rep));
if (pbuf->ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr == pbuf->pktinfo.haBindingCOA && IP_BIT_ISFALSE(req->flags, IPMIP4_REG_EXT_UDP_FLAG_FORCED))
rep.code = 64;
else
{
IP_BIT_SET(pbuf->pktinfo.haBindingTunnelFlags, IPMIP4_TUNNELMODE_NAT_T_RECEIVED);
if (encap != IPMIP_TUNNELTYPE_NONE &&
encap != pbuf->pktinfo.haBindingTunnelType)
{
if (pbuf->iff.priv->tunnel.enabled[encap] == IP_FALSE)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to nat traversal encapsulation %s unavailable (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
ipmip_util_tunnel_to_name(encap),
IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ENCAP_UNAVAIL);
}
pbuf->pktinfo.haBindingTunnelType = encap;
}
}
rep.keep_alive = ip_htons(pbuf->iff.priv->nat_t_keepalive);
rep.type = IPMIP4_EXT_TYPE_UDP_TUNNEL_REP;
rep.length = sizeof(rep) - 2;
rep.flags = req->flags & IPMIP4_REG_EXT_UDP_FLAG_FORCED;
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.udp_tunnel_req, pbuf->pktinfo.haBindingInnerAuth))
ipmip4_msgext_buffer_append_shdr(&pbuf->reply_mn, (void *)&rep);
else
ipmip4_msgext_buffer_append_shdr(&pbuf->reply_fa, (void *)&rep);
}
}
}
/* FALL THROUGH */
case IPMIPHA_REG_REQUEST_HOME_ADDRESS:
if (node->haNodeHomeAddress.prefix != 0)
pbuf->pktinfo.haBindingHomeAddress = node->haNodeHomeAddress.prefix;
else if (pbuf->pktinfo.haBindingResolvedHomeAddress != 0)
pbuf->pktinfo.haBindingHomeAddress = pbuf->pktinfo.haBindingResolvedHomeAddress;
if (pbuf->pktinfo.haBindingHomeAddress == 0)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to unable to assign home address to request (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT);
}
if (IP_BIT_ISFALSE(node->state, IPMIPHA_NODE_STATE_HOME_ADDRESS))
{
/**/
if (node->haNodeHomeAddress.prefix == 0 && !ipmipha_node_home_address_assign(data, proc, node, pbuf->pktinfo.haBindingHomeAddress))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to home address collision in dynamic assignment (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_ADMIN_PROHIBIT);
}
IP_BIT_SET(node->state, IPMIPHA_NODE_STATE_HOME_ADDRESS);
}
/* FALL THROUGH */
case IPMIPHA_REG_REQUEST_BINDING_UPDATE:
/* */
if (pbuf->pktinfo.haBindingTimeGranted == 0)
{
if (pbuf->pktinfo.haBindingCOA == node->haNodeHomeAddress.prefix)
{
/* Complete de-registration */
ipmipha_node_binding_delete(data, proc, node, IP_NULL);
ipmipha_node_silence(data, proc, node);
}
else if (binding != IP_NULL)
{
/* Delete this particular binding */
ipmipha_node_binding_delete(data, proc, node, binding);
}
/* Remove the pointers to this binding */
pbuf->binding = IP_NULL;
binding = IP_NULL;
}
else
{
/**/
if (binding == IP_NULL)
{
if (pbuf->iff.priv->simbind_enabled && IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_SIM_BINDINGS))
{
Ipmipha_node_binding_t *collission;
/* Too many simbinds? */
if (node->bindings.size >= pbuf->iff.priv->simbind_max)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to too many simultaneous bindings (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_TOO_MANY_SIM));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_TOO_MANY_SIM);
}
collission = ipmipha_node_binding_endpoint(data, proc, node, pbuf->pktinfo.haBindingTunnelEndpoint);
/* If we collide; revoke the colliding endpoint */
if (collission)
{
IPMIP4_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Node %s registration of binding collided with a previous binding due to NAT-T. Old binding deleted",
ipmipha_node_describe(proc, node, binding)));
ipmipha_node_binding_delete(data, proc, node, collission);
}
}
else
{
if (IP_BIT_ISSET(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_SIM_BINDINGS))
{
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haMultiBindingUnsupported, 1);
pbuf->pktinfo.haBindingHAErrorCode = IPMIP4_CODE_REP_REG_ACCEPTED_BUT_NO_SIM_BINDS;
}
/* No SIM binds; revoke all other */
IPMIP4_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Node %s is moving, revoke old bindings",
ipmipha_node_describe(proc, node, binding)));
ipmipha_node_binding_revoke(data, proc, node, IP_NULL, IPMIP_SYSVAR_MODE_OPTIONAL, IP_TRUE);
}
/**/
binding = ipmipha_node_binding_create(data, proc, node, pbuf);
/* */
if (binding == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to out of memory allocating binding (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES));
return ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_INSUFFICIENT_RESOURCES);
}
/* reregister */
IPMIP4_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Node %s registered",
ipmipha_node_describe(proc, node, binding)));
}
else
{
/* reregister */
IPMIP4_EVENT_IF(DEBUG2, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Node %s re-registered",
ipmipha_node_describe(proc, node, binding)));
ipmipha_node_binding_update(data, proc, node, binding, pbuf);
}
/**/
ipmipha_node_function_request_accept(data, proc, node, binding, pbuf);
}
/* */
IPMIPHA_MIB_COUNTER_ADD(data, data->mibRegCounters.haRegistrationAccepted, 1);
/* Update security associations */
ipmipha_node_security_associations(data, proc, node, binding, pbuf);
case IPMIPHA_REG_REQUEST_ENABLE:
pbuf->pktinfo.haBindingParsingState = IPMIPHA_REG_REQUEST_ENABLE;
if (ipmipha_node_enable(data, proc, node))
return IPMIP_TIMER_RET_PENDING;
/* Reply */
ipmipha_reg_reply(data, proc, node, pbuf);
break;
}
return IPMIP_TIMER_RET_DONE;
}
else
{
/* Cancelled or aborted */
ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip);
return IPMIP_TIMER_RET_DONE;
}
}
/*
*===========================================================================
* ipmipha_reg_input_parse_request
*===========================================================================
* Description: Parses basic values in a registration request.
* Parameters: data - Data context
* proc - Process
* pbuf - Packet buffer.
* Returns: IP_TRUE on success
*
*/
IP_GLOBAL Ip_bool
ipmipha_reg_input_parse_request(Ipmipha_data_t *data,
Ipmip_proc_t *proc,
Ipmipha_pktbuf_t *pbuf)
{
/* Check length */
if (IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet) < IPMIP4_REGREQ_LENGTH)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"Truncated registration request [%d]", IPMIP_BUFFER_SIZE(&pbuf->ipmip4.ipmip.packet)));
ipmipha_reg_request_error(data, proc, pbuf, 0);
return IP_FALSE;
}
else
{
/* Pointers to the packet */
Ipmip4_regreq_t *regreq = IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet);
/* Store pending reg information */
pbuf->pktinfo.haBindingRegIDLow = IP_GET_32ON8(&regreq->id[1]);
pbuf->pktinfo.haBindingRegIDHigh = IP_GET_32ON8(&regreq->id[0]);
pbuf->pktinfo.haBindingHomeAgentAddress = IP_GET_32ON8(&regreq->home_agent);
pbuf->pktinfo.haBindingHomeAddress = IP_GET_32ON8(&regreq->home_addr);
pbuf->pktinfo.haBindingHomeAddressRequested = pbuf->pktinfo.haBindingHomeAddress;
pbuf->pktinfo.haBindingTimeGranted = IP_GET_HTONS(&regreq->lifetime);
pbuf->pktinfo.haBindingTimeGranted = IP_MIN(pbuf->pktinfo.haBindingTimeGranted, pbuf->iff.priv->lifetime);
/* Store vital registration information */
pbuf->pktinfo.haBindingCOA = IP_GET_32ON8(&regreq->care_of_addr);
pbuf->pktinfo.haBindingTunnelEndpoint = pbuf->pktinfo.haBindingCOA;
pbuf->pktinfo.haBindingRegFlags = regreq->code;
/* If its a DHAA request; make certain to home address isn't explicitly set */
if ((pbuf->pktinfo.haBindingHomeAgentAddress == 0 || pbuf->pktinfo.haBindingHomeAgentAddress == 0xffffffff))
{
/* This home address is tentative; dont be too certain about it */
pbuf->pktinfo.haBindingHomeAddress = 0;
}
}
/* OK */
pbuf->ipmip4.ext.mobile.result = ipmip4_msgext_mobile_parse_ext(&data->ipmip4, proc, &pbuf->ipmip4, IPMIP4_REGREQ_LENGTH);
/* Parse extensions */
switch (pbuf->ipmip4.ext.mobile.result)
{
case IPMIP4_REG_EXT_FAILED_AUTH:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to bad or duplicate authentication extensions (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_FA_MN_FAILED_AUTH));
ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_MN_FAILED_AUTH);
return IP_FALSE;
case IPMIP4_REG_EXT_POORLY_FORMED:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to poorly formed request (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_FA_MN_FAILED_AUTH));
ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_POORLY_FORMED_REQUEST);
return IP_FALSE;
case IPMIP4_REG_EXT_DISCARD:
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
ipmipha_reg_request_error(data, proc, pbuf, 0);
return IP_FALSE;
}
/* Do we have an error code? */
if (pbuf->ipmip4.ipmip.message != 0)
return IP_FALSE;
/* Process this packet buffer */
/* No mobile home? */
/* No mobile home? */
if (pbuf->ipmip4.ext.mobile.mobile_home == IP_NULL && pbuf->ipmip4.ext.mobile.mn_aaa == IP_NULL)
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to no mobile-home authentication or mn-aaa extension header found",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
ipmipha_reg_request_error(data, proc, pbuf, 0);
return IP_FALSE;
}
else if (pbuf->ipmip4.ext.mobile.mobile_home && pbuf->ipmip4.ext.mobile.mn_aaa && IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.mn_aaa, pbuf->ipmip4.ext.mobile.mobile_home))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to mn-aaa extension within mobile-home authentication",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
ipmipha_reg_request_error(data, proc, pbuf, 0);
return IP_FALSE;
}
if (pbuf->ipmip4.ext.mobile.mobile_home != IP_NULL)
{
pbuf->pktinfo.haBindingInnerAuth = pbuf->ipmip4.ext.mobile.mobile_home;
pbuf->pktinfo.haBindingInnerAuthSize = IPMIP4_MSGEXT_SHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.mobile_home);
pbuf->pktinfo.haBindingMobileHomeSAPolicyOK = IP_TRUE;
}
if (pbuf->ipmip4.ext.mobile.foreign_home != IP_NULL)
{
pbuf->pktinfo.haBindingOuterAuth = pbuf->ipmip4.ext.mobile.foreign_home;
pbuf->pktinfo.haBindingOuterAuthSize = IPMIP4_MSGEXT_SHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.foreign_home);
pbuf->pktinfo.haBindingForeignHomeSAPolicyOK = IP_TRUE;
}
/**/
if (pbuf->ipmip4.ext.mobile.mn_aaa != IP_NULL)
{
pbuf->pktinfo.haBindingAAAAuth = pbuf->ipmip4.ext.mobile.mn_aaa;
pbuf->pktinfo.haBindingAAAAuthSize = IPMIP4_MSGEXT_LHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.mn_aaa);
if (pbuf->pktinfo.haBindingInnerAuth == IP_NULL)
{
pbuf->pktinfo.haBindingInnerAuth = pbuf->pktinfo.haBindingAAAAuth;
pbuf->pktinfo.haBindingInnerAuthSize = pbuf->pktinfo.haBindingAAAAuthSize;
}
if (pbuf->pktinfo.haBindingOuterAuth == IP_NULL)
{
pbuf->pktinfo.haBindingOuterAuth = pbuf->pktinfo.haBindingAAAAuth;
pbuf->pktinfo.haBindingOuterAuthSize = pbuf->pktinfo.haBindingAAAAuthSize;
}
}
else
{
pbuf->pktinfo.haBindingAAAAuth = pbuf->ipmip4.ext.mobile.mobile_home;
pbuf->pktinfo.haBindingAAAAuthSize = IPMIP4_MSGEXT_SHDR_TOT_SIZE(pbuf->ipmip4.ext.mobile.mobile_home);
}
/* Truncate; remove any mobile to foreign data */
ipmip_buffer_shrink(&pbuf->ipmip4.ipmip.packet,
((Ip_u8 *)pbuf->pktinfo.haBindingAAAAuth - (Ip_u8 *)IPMIP_BUFFER_DATA(&pbuf->ipmip4.ipmip.packet)) + pbuf->pktinfo.haBindingAAAAuthSize);
/* Dont use a NAI that's not authenticated */
if (pbuf->ipmip4.ext.mobile.nai_mobile != IP_NULL && IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.nai_mobile, pbuf->pktinfo.haBindingInnerAuth) == IP_FALSE)
pbuf->ipmip4.ext.mobile.nai_mobile = IP_NULL;
/* Do we have a foreign-home authentication? */
if (pbuf->pktinfo.haBindingForeignHomeSAPolicyOK == IP_FALSE)
{
/* Do we require it? */
if (pbuf->pktinfo.haBindingTimeGranted != 0 &&
pbuf->iff.priv->fa_auth != 0 &&
IP_BIT_ISFALSE(pbuf->pktinfo.haBindingRegFlags, IPMIP4_CODE_REQ_DECAPSULATION))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request discarded due to required foreign-home authentication extension header not found (%d)",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA),
IPMIP4_CODE_REP_HA_FA_FAILED_AUTH));
ipmipha_reg_request_error(data, proc, pbuf, IPMIP4_CODE_REP_HA_FA_FAILED_AUTH);
return IP_FALSE;
}
pbuf->pktinfo.haBindingForeignHomeSAPolicyOK = IP_TRUE;
}
if (pbuf->ipmip4.ext.mobile.challenge)
{
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.challenge, pbuf->ipmip4.ext.mobile.mobile_home))
{
/* The challenge is not part of the MF authentication extension */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to challenge extension within mobile-home authentication",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
ipmipha_reg_request_error(data, proc, pbuf, 0);
return IP_FALSE;
}
if (IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.challenge, pbuf->pktinfo.haBindingAAAAuth) == IP_FALSE)
{
/* The challenge is not part of the MF authentication extension */
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to challenge extension not properly protected with mobile-foreign authentication",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
ipmipha_reg_request_error(data, proc, pbuf, 0);
return IP_FALSE;
}
}
/* Verify keyreq */
if (pbuf->ipmip4.ext.mobile.mn_ha_keyreq != IP_NULL && !IPMIP4_MSGEXT_AUTHENTICATED(pbuf->ipmip4.ext.mobile.mn_ha_keyreq, pbuf->ipmip4.ext.mobile.mn_aaa))
{
IPMIP4_EVENT_IF(WARNING, proc,
ipmip_log_event_add(&data->ipmip4.ipmip,
proc,
"%s@%s[%s] registration request silently discarded due to mn-ha key generation request not protected by mn-aaa authentication extension",
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingHomeAddress),
pbuf->iff.pub->ipmip.ifname,
ipmip_ntop_inet(proc, pbuf->pktinfo.haBindingCOA)));
ipmipha_reg_request_error(data, proc, pbuf, 0);
return IP_FALSE;
}
return IP_TRUE;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/