2417 lines
88 KiB
C
2417 lines
88 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipmn_if.c,v $ $Revision: 1.33.10.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmipmn/src/ipmipmn_if.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 "ipmipmn_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_ipd.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock2.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_netif.h> /* for IP_IFT_ETHER */
|
|
#include <ipcom_shell.h>
|
|
|
|
#include <ipnet_routesock.h>
|
|
#include <ipnet_eth.h>
|
|
|
|
#ifdef IPIPSEC2
|
|
#include <ipipsec.h>
|
|
#include <ipipsec_pfkeyv2.h>
|
|
#endif
|
|
|
|
#ifdef IPIKE
|
|
#include <ipike.h>
|
|
#endif
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_timer.h>
|
|
#include <private/ipmip_sysvar.h>
|
|
|
|
#include <ipmip4.h>
|
|
#include <private/ipmip4_context.h>
|
|
#include <private/ipmip4_auth.h>
|
|
#include <private/ipmip4_lla.h>
|
|
#include <private/ipmip4_util.h>
|
|
#include <private/ipmip4_sysext.h>
|
|
#include <private/ipmip4_if.h>
|
|
#include <private/ipmip4_pkt.h>
|
|
#include <private/ipmip4_usr.h>
|
|
#include <private/ipmip4_netlink.h>
|
|
|
|
#include "ipmipmn.h"
|
|
#include "ipmipmn_h.h"
|
|
#include "ipmipmn_if.h"
|
|
#include "ipmipmn_pktbuf.h"
|
|
#include "ipmipmn_route.h"
|
|
#include "ipmipmn_node.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
typedef struct Ipmipmn_if_sainfo
|
|
{
|
|
Ip_bool tunnel;
|
|
Ip_u32 srcaddr;
|
|
} Ipmipmn_if_sainfo_t;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_reference
|
|
*===========================================================================
|
|
* Description: Reference the CoA
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* coa - CoA
|
|
* Returns: The CoA
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmipmn_if_coa_reference_iflocked(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_api_coa_t *coa,
|
|
Ip_bool sysref,
|
|
const char *reason)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
if (!sysref || !coa->sysref)
|
|
{
|
|
if (sysref)
|
|
coa->sysref = IP_TRUE;
|
|
coa->refcnt++;
|
|
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA=%s upped refcount (%s) to %d (%s)",
|
|
coa->name,
|
|
sysref? "system" : "normal",
|
|
coa->refcnt,
|
|
reason));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_dereference_iflocked
|
|
*===========================================================================
|
|
* Description: Reference the CoA
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* coa - CoA
|
|
* Returns: The CoA
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipmipmn_if_coa_dereference_iflocked(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_api_coa_t *coa,
|
|
Ip_bool sysref,
|
|
const char *reason)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
if (!sysref || coa->sysref)
|
|
{
|
|
if (sysref)
|
|
coa->sysref = IP_FALSE;
|
|
coa->refcnt--;
|
|
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA=%s downed refcount (%s) to %d (%s)",
|
|
coa->name,
|
|
sysref? "system" : "normal",
|
|
coa->refcnt,
|
|
reason));
|
|
|
|
|
|
return coa->refcnt == 0;
|
|
}
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_notify_iflocked
|
|
*===========================================================================
|
|
* Description: Schedule callbacks.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmipmn_if_notify_iflocked(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
Ipmipmn_iff_notify_t *notifier;
|
|
for (ifp = IPCOM_LIST_FIRST(&data->ifhead); ifp != IP_NULL; ifp = IPCOM_LIST_NEXT(&ifp->iff.ipmip.next))
|
|
{
|
|
for (notifier = IPCOM_LIST_FIRST(&ifp->notifiers); notifier != IP_NULL; notifier = IPCOM_LIST_NEXT(¬ifier->if_next))
|
|
{
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, ¬ifier->timer);
|
|
ipmip_timer_request(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
¬ifier->timer,
|
|
notifier->lock,
|
|
notifier->func,
|
|
notifier->obj,
|
|
ifp,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_ifstate_iflocked
|
|
*===========================================================================
|
|
* Description: Verify interface state
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - The interface
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmipmn_if_ifstate_iflocked(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
Ip_bool down = ifp->admin_down || ifp->link_down;
|
|
if (down != ifp->down)
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Interface %s is administratively brought %s",
|
|
ifp->iff.ipmip.ifname, down? "down" : "up"));
|
|
ifp->down = down;
|
|
if (ifp->down)
|
|
ifp->sync_count++;
|
|
ipmipmn_if_notify_iflocked(data, proc, ifp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_route_destroy_tunnel
|
|
*===========================================================================
|
|
* Description: Destroy a particular tunnel.
|
|
* Parameters: tunnel - The tunnel to destroy.
|
|
* Returns:
|
|
*/
|
|
IP_STATIC void
|
|
ipmipmn_if_destroy(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *iff)
|
|
{
|
|
/* No tunnel, don't bother */
|
|
if (iff->iff.ipmip.ifindex == 0)
|
|
return;
|
|
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_get_iflocked
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipmipmn_iff_t *
|
|
ipmipmn_if_get_iflocked(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
const char *name)
|
|
{
|
|
/* Go through the interface list */
|
|
Ipmipmn_iff_t *ifp = (Ipmipmn_iff_t *)ipmip_if_findbyname(&data->ifhead, (char *)name);
|
|
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
if (ifp != IP_NULL)
|
|
ifp->references++;
|
|
|
|
return ifp;
|
|
}
|
|
|
|
IP_STATIC Ipmipmn_iff_t *
|
|
ipmipmn_if_getbyindex_iflocked(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
int ifindex)
|
|
{
|
|
Ipmipmn_iff_t *ifp;
|
|
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
/* Go through the interface list */
|
|
ifp = (Ipmipmn_iff_t *)ipmip_if_findbyindex(&data->ifhead, ifindex);
|
|
if (ifp != IP_NULL)
|
|
ifp->references++;
|
|
|
|
return ifp;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_put_iflocked
|
|
*===========================================================================
|
|
* Description: Return a previously retrieved CoA
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* coa - CoA
|
|
* Returns: IP_TRUE if the CoA was deleted.
|
|
*
|
|
*/
|
|
IP_STATIC Ip_bool
|
|
ipmipmn_if_coa_put_iflocked(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *coa,
|
|
Ip_bool hide,
|
|
Ip_bool system,
|
|
const char *reason)
|
|
{
|
|
Ip_bool dele = IP_FALSE;
|
|
if (ipmipmn_if_coa_dereference_iflocked(data, proc, coa, system, reason))
|
|
{
|
|
dele = IP_TRUE;
|
|
if (ipmipmn_if_coa_valid(coa))
|
|
ipcom_list_remove(&coa->next);
|
|
|
|
ifp->allocated--;
|
|
|
|
IPMIP4_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA '%s' removed from interface '%s' (%d)",
|
|
coa->name,
|
|
ifp->iff.ipmip.ifname,
|
|
ifp->allocated));
|
|
|
|
switch (coa->type)
|
|
{
|
|
case IPMIPMN_ATTR_COA_CCOA:
|
|
/* FALL THROUGH */
|
|
|
|
case IPMIPMN_ATTR_COA_SCOA_TIA:
|
|
case IPMIPMN_ATTR_COA_SCOA_PROTECTED:
|
|
break;
|
|
case IPMIPMN_ATTR_COA_FA:
|
|
case IPMIPMN_ATTR_COA_FA_LLH:
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, &coa->params.fa.timer);
|
|
if (coa->params.fa.lladdr)
|
|
ipcom_free(coa->params.fa.lladdr);
|
|
if (coa->params.fa.lladdr_llh)
|
|
ipcom_free(coa->params.fa.lladdr_llh);
|
|
if (coa->params.fa.challenge)
|
|
ipcom_free(coa->params.fa.challenge);
|
|
break;
|
|
case IPMIPMN_ATTR_COA_HA:
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, &coa->params.ha.timer);
|
|
if (coa->params.ha.lladdr)
|
|
ipcom_free(coa->params.ha.lladdr);
|
|
break;
|
|
}
|
|
ipcom_free(coa->name);
|
|
ipcom_free(coa);
|
|
}
|
|
else if (hide)
|
|
{
|
|
if (ipmipmn_if_coa_valid(coa))
|
|
ipcom_list_remove(&coa->next);
|
|
}
|
|
|
|
return dele;
|
|
}
|
|
|
|
|
|
IP_STATIC int
|
|
ipmipmn_if_agent_timeout_iflocked(int event,
|
|
Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_api_coa_t *agent,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
/**/
|
|
if (event == IPMIP_TIMER_EVENT_RUN)
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA '%s' timed out",
|
|
agent->name));
|
|
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, agent, IP_TRUE, IP_TRUE, "CoA Timed Out");
|
|
ipmipmn_if_notify_iflocked(data, proc, ifp);
|
|
}
|
|
|
|
return IPMIP_TIMER_RET_DONE;
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipmn_if_put_iflocked(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
if (--ifp->references == 0)
|
|
{
|
|
Ipmipmn_api_coa_t *coa;
|
|
for (coa = IPCOM_LIST_FIRST(&ifp->coa); coa != IP_NULL;)
|
|
{
|
|
Ipmipmn_api_coa_t *ncoa = IPCOM_LIST_NEXT(&coa->next);
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, coa, IP_FALSE, IP_TRUE, "Interface removed");
|
|
coa = ncoa;
|
|
}
|
|
|
|
/* MUST BE EMPTY, OR WE'LL HAVE DANGLING REFERENCES */
|
|
ip_assert(ifp->coa.size == 0);
|
|
ip_assert(ifp->allocated == 0);
|
|
|
|
data->ifalloc--;
|
|
IPMIP4_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Interface '%s' removed (%d)",
|
|
ifp->iff.ipmip.
|
|
ifname, data->ifalloc));
|
|
|
|
/* Free the interface */
|
|
ipmip_if_free(&data->api.ipmip4.ipmip, proc, &ifp->iff.ipmip);
|
|
return IP_TRUE;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
#ifdef IPIPSEC2
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipmn_if_get_sainfo(Ipipsec_sa_handle *sa,
|
|
Ipmipmn_if_sainfo_t *sainfo)
|
|
{
|
|
Ip_tag tags[7];
|
|
int retval;
|
|
|
|
/* Get additional information. */
|
|
tags[0] = IPIPSEC_SACTRLT_GET_Encapsulation;
|
|
tags[1] = 0;
|
|
tags[2] = IPIPSEC_SACTRLT_GET_SrcAddr;
|
|
tags[3] = 0;
|
|
tags[4] = IP_TAG_END;
|
|
|
|
retval = ipipsec_sactrl(sa, tags);
|
|
if (retval != IPCOM_SUCCESS)
|
|
{
|
|
ipcom_printf("ipsecctrl: ipipsec_sactrl(info) failed, error = %d"IP_LF, retval);
|
|
return IP_FALSE;
|
|
}
|
|
|
|
sainfo->tunnel = tags[1] == 1;
|
|
sainfo->srcaddr = tags[3];
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipmn_if_secure_verify_spd(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipipsec_ctrl_selector *sel,
|
|
int dir)
|
|
{
|
|
const char *dstr = dir == IPIPSEC_SADIR_INPUT? "inbound" : "outbound";
|
|
|
|
/* Only interested in INET */
|
|
if (sel->domain != IP_AF_INET)
|
|
return IP_FALSE;
|
|
|
|
/* Only parse inbound to start with */
|
|
if (sel->direction != dir)
|
|
return IP_FALSE;
|
|
|
|
/* Require a SA */
|
|
if (sel->sa.domain != IP_AF_INET)
|
|
return IP_FALSE;
|
|
|
|
/* We got a selector; MUST BE WILDCARDED - NO PORTS or PROTOCOLS */
|
|
if (sel->LocalPort || sel->RemotePort || sel->Protocol)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Discarding %s selector due to specified protocol or ports",
|
|
dstr));
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmipmn_if_secure_isbound(Ipmip_buffer_t *reply,
|
|
Ip_u32 addr)
|
|
{
|
|
struct Ip_nlmsghdr *nlh = IPMIP_BUFFER_PTR(reply);
|
|
Ip_size_t nlh_size = IPMIP_BUFFER_SIZE(reply);
|
|
|
|
/* Verify that the address exists */
|
|
while (IP_NLMSG_OK(nlh, nlh_size))
|
|
{
|
|
/**/
|
|
if (nlh->nlmsg_type == IP_RTM_NEWADDR)
|
|
{
|
|
struct Ip_ifaddrmsg *ifa = IP_NLMSG_DATA(nlh);
|
|
struct Ip_rtattr *ifap[IP_IFA_MAX + 1];
|
|
|
|
/* Resolve this entry; I want the prefix length and the address */
|
|
ipmip_netlink_nlmsghdr_rta_parse(IP_IFA_MAX + 1,
|
|
IP_IFA_RTA(ifa),
|
|
IP_IFA_PAYLOAD(nlh),
|
|
ifap);
|
|
|
|
/* Found one */
|
|
if (ifap[IP_IFA_LOCAL] && addr == IP_GET_32ON8(IP_RTA_DATA(ifap[IP_IFA_LOCAL])))
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/**/
|
|
nlh = IP_NLMSG_NEXT(nlh, nlh_size);
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
#ifdef IPIKE
|
|
IP_STATIC void
|
|
ipmipmn_if_ike_move(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *coa,
|
|
Ip_u32 addr)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Trying to move IKE endpoint %s -> %s",
|
|
ipmip_ntop_inet(proc, addr),
|
|
ipmip_ntop_inet(proc, coa->addr)));
|
|
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(ifp);
|
|
|
|
/* Is it started? */
|
|
if (ipcom_ipd_send("ipike", IPCOM_IPD_MSGTYPE_PING) == IPCOM_SUCCESS)
|
|
{
|
|
Ipmip_buffer_t buf;
|
|
Ipcom_ipd_msg hdr;
|
|
char *argbuf;
|
|
|
|
ipmip_buffer_init(&buf);
|
|
|
|
ipcom_memset(&hdr, 0, sizeof(hdr));
|
|
hdr.msgtype = IPIKE_CMD_MOBIKE;
|
|
|
|
ipmip_buffer_append(&buf, &hdr, sizeof(hdr));
|
|
|
|
argbuf = ipmip_util_strdup("%s %s", ipmip_ntop_inet(proc, addr), ipmip_ntop_inet(proc, coa->addr));
|
|
if (argbuf)
|
|
{
|
|
ipmip_buffer_append(&buf, argbuf, ipcom_strlen(argbuf) + 1);
|
|
|
|
if (ipcom_ipd_sendmsg("ipike", IPMIP_BUFFER_PTR(&buf), IPMIP_BUFFER_SIZE(&buf)) == IPCOM_SUCCESS)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Trying to move IKE endpoint %s -- success",
|
|
argbuf));
|
|
}
|
|
else
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Trying to move IKE endpoint %s -- failed",
|
|
argbuf));
|
|
}
|
|
ipcom_free(argbuf);
|
|
}
|
|
|
|
ipmip_buffer_release(&buf);
|
|
}
|
|
else
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"IKE not started"));
|
|
}
|
|
}
|
|
#endif /* IPIKE */
|
|
|
|
#endif
|
|
|
|
|
|
IP_STATIC int
|
|
ipmipmn_if_coa_type(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip_buffer_t *reply,
|
|
Ip_u32 addr,
|
|
Ipmipmn_api_coa_params_t *cparam)
|
|
{
|
|
#ifdef IPIPSEC2
|
|
Ip_err retval;
|
|
Ipipsec_ctrl_selector isel;
|
|
Ipipsec_ctrl_selector osel;
|
|
Ipmipmn_if_sainfo_t sainfo;
|
|
|
|
isel.Index = 0; /* get first selector. */
|
|
|
|
for(;;)
|
|
{
|
|
Ip_bool tia = IP_TRUE;
|
|
|
|
/* Get first/next Selector */
|
|
retval = ipmip_util_ioctl(&data->api.ipmip4.ipmip, proc, IP_SIOCXIPSEC_SELECTOR, &isel);
|
|
if(retval != IPCOM_SUCCESS)
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Selector print aborted: error = %d", retval));
|
|
|
|
goto bail_out;
|
|
}
|
|
|
|
/* */
|
|
if(isel.Index == 0)
|
|
break;
|
|
|
|
/* Do verify the SPD */
|
|
if (!ipmipmn_if_secure_verify_spd(data, proc, &isel, IPIPSEC_SADIR_INPUT))
|
|
continue;
|
|
|
|
if (addr != isel.RemoteId.in.s_addr)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Non-TIA address due to mismatching addresses (%s != %s)",
|
|
ipmip_ntop_inet(proc, addr),
|
|
ipmip_ntop_inet(proc, isel.RemoteId.in.s_addr)));
|
|
tia = IP_FALSE;
|
|
}
|
|
|
|
if (tia && isel.remote_mask.in.s_addr != 0xffffffff)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Non-TIA to non-explicit host mask (%s)",
|
|
ipmip_ntop_inet(proc, isel.remote_mask.in.s_addr)));
|
|
tia = IP_FALSE;
|
|
}
|
|
|
|
/* Now; We got an inbound selector */
|
|
/* Must be protected by a different address */
|
|
if (tia && isel.RemoteId.in.s_addr == isel.sa.dst.in.s_addr)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Non-TIA due to sa destination and remote destination are equal (%s)",
|
|
ipmip_ntop_inet(proc, isel.sa.dst.in.s_addr)));
|
|
tia = IP_FALSE;
|
|
}
|
|
|
|
if (!tia)
|
|
{
|
|
/* Match against mask */
|
|
if ((addr & isel.remote_mask.in.s_addr) != (isel.RemoteId.in.s_addr & isel.remote_mask.in.s_addr))
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Discarding inbound selector (%s/%s) due to SPD not properly covering the address(%s)",
|
|
ipmip_ntop_inet(proc, isel.RemoteId.in.s_addr),
|
|
ipmip_ntop_inet(proc, isel.remote_mask.in.s_addr),
|
|
ipmip_ntop_inet(proc, addr)));
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Verify the scoa */
|
|
if (!ipmipmn_if_secure_isbound(reply, isel.RemoteId.in.s_addr))
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Discarding inbound selector due to remote destination not bound"));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Verify the end-point */
|
|
if (!ipmipmn_if_secure_isbound(reply, isel.sa.dst.in.s_addr))
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Discarding inbound selector due to SA destination not bound"));
|
|
/**/
|
|
/* Current anchor address */
|
|
continue;
|
|
}
|
|
|
|
|
|
/* OK; Verify that we've gotten an outbound flow */
|
|
osel.Index = 0; /* get first selector. */
|
|
|
|
for(;;)
|
|
{
|
|
/* Get first/next Selector */
|
|
retval = ipmip_util_ioctl(&data->api.ipmip4.ipmip, proc, IP_SIOCXIPSEC_SELECTOR, &osel);
|
|
if(retval != IPCOM_SUCCESS)
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Selector print aborted: error = %d", retval));
|
|
goto bail_out;
|
|
}
|
|
|
|
/* */
|
|
if(osel.Index == 0)
|
|
break;
|
|
|
|
/* Do verify the SPD */
|
|
if (!ipmipmn_if_secure_verify_spd(data, proc, &osel, IPIPSEC_SADIR_OUTPUT))
|
|
continue;
|
|
|
|
/* Local origin must be the same as remote destination */
|
|
if (osel.LocalId.in.s_addr != isel.RemoteId.in.s_addr ||
|
|
osel.local_mask.in.s_addr != isel.remote_mask.in.s_addr)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Discarding outbound selector due inbound(%s)/outbound(%s) mismatch",
|
|
ipmip_ntop_inet(proc, isel.RemoteId.in.s_addr),
|
|
ipmip_ntop_inet(proc, osel.LocalId.in.s_addr)));
|
|
continue;
|
|
}
|
|
|
|
if (!ipmipmn_if_get_sainfo(&osel.sa, &sainfo))
|
|
continue;
|
|
|
|
/* Verify the end-point */
|
|
if (!ipmipmn_if_secure_isbound(reply, sainfo.srcaddr))
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Discarding outbound selector due to SA destination not bound"));
|
|
|
|
/**/
|
|
/* Current anchor address */
|
|
continue;
|
|
}
|
|
|
|
if (tia && sainfo.tunnel == IP_FALSE)
|
|
{
|
|
IPMIP4_EVENT_IF(DEBUG2, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA Type/IPIPSEC: Non-TIA due to sa does not tunnel"));
|
|
tia = IP_FALSE;
|
|
}
|
|
|
|
/* Store TIA information */
|
|
if (tia)
|
|
{
|
|
cparam->tia.ike_address = osel.sa.dst.in.s_addr;
|
|
cparam->tia.local_address = sainfo.srcaddr;
|
|
}
|
|
|
|
/* We're successful; check this particular address */
|
|
if (tia)
|
|
return IPMIPMN_ATTR_COA_SCOA_TIA;
|
|
else
|
|
return IPMIPMN_ATTR_COA_SCOA_PROTECTED;
|
|
}
|
|
}
|
|
bail_out:
|
|
#else
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(reply);
|
|
IPMIP_UNUSED_PARAMETER(addr);
|
|
IPMIP_UNUSED_PARAMETER(cparam);
|
|
#endif
|
|
|
|
return IPMIPMN_ATTR_COA_CCOA;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_relink_iflocked
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmipmn_if_coa_relink_iflocked(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *coa,
|
|
Ip_bool first)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
if (ipmipmn_if_coa_valid(coa))
|
|
{
|
|
ipcom_list_remove(&coa->next);
|
|
if (first)
|
|
ipcom_list_insert_first(&ifp->coa, &coa->next);
|
|
else
|
|
ipcom_list_insert_last(&ifp->coa, &coa->next);
|
|
}
|
|
}
|
|
|
|
IP_STATIC int
|
|
ipmipmn_if_coa_output_send(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_node_t *node,
|
|
Ipmipmn_pktbuf_t *pbuf,
|
|
struct Ipmipmn_api_coa *coa,
|
|
Ip_bool deregister,
|
|
Ip_u32 src,
|
|
Ip_u32 dst,
|
|
void *exdata)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(deregister);
|
|
IPMIP_UNUSED_PARAMETER(coa);
|
|
IPMIP_UNUSED_PARAMETER(exdata);
|
|
|
|
if (node->api.params.mnRegCoA->peer == IPMIPMN_ATTR_PEER_FOREIGN_AGENT)
|
|
{
|
|
if (!ipmip4_pkt_udp_write(&data->api.ipmip4,
|
|
proc,
|
|
&pbuf->api.ipmip4.ipmip.packet,
|
|
src,
|
|
data->api.ipmip4.pkt->s_udp_out.sin_port,
|
|
dst,
|
|
ip_htons(IPMIP4_PORT),
|
|
node->api.params.pubIf,
|
|
node->api.params.mnRegCoA->params.fa.lladdr))
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"%s unable to write request errno=%d",
|
|
IPMIPMN_API_NODE_NAME(&data->api, proc, &node->api),
|
|
ipcom_errno));
|
|
return -1;
|
|
}
|
|
}
|
|
else if (node->api.params.mnRegCoA->type == IPMIPMN_ATTR_COA_HA)
|
|
{
|
|
if (!ipmip4_pkt_udp_write(&data->api.ipmip4,
|
|
proc,
|
|
&pbuf->api.ipmip4.ipmip.packet,
|
|
src,
|
|
data->api.ipmip4.pkt->s_udp_out.sin_port,
|
|
dst,
|
|
ip_htons(IPMIP4_PORT),
|
|
node->api.params.pubIf,
|
|
node->api.params.mnRegCoA->params.ha.lladdr))
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"%s unable to send de-registration request errno=%d",
|
|
IPMIPMN_API_NODE_NAME(&data->api, proc, &node->api),
|
|
ipcom_errno));
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ipmip4_pkt_udp_sendmsg(&data->api.ipmip4,
|
|
proc,
|
|
&pbuf->api.ipmip4.ipmip.packet,
|
|
src,
|
|
data->api.ipmip4.pkt->s_udp_out.sin_port,
|
|
dst,
|
|
ip_htons(IPMIP4_PORT),
|
|
node->api.params.pubIf) == IP_FALSE)
|
|
{
|
|
IPMIP4_EVENT_IF(WARNING, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"%s unable to send request errno=%d",
|
|
IPMIPMN_API_NODE_NAME(&data->api, proc, &node->api),
|
|
ipcom_errno));
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_new_iflocked
|
|
*===========================================================================
|
|
* Description: Create a CoA of a specific type.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* addr - Address
|
|
* type - Type of CoA
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipmipmn_api_coa_t *
|
|
ipmipmn_if_coa_new_iflocked(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ip_u32 addr,
|
|
Ip_u32 type,
|
|
Ip_bool first,
|
|
Ipmipmn_api_coa_params_t *param)
|
|
{
|
|
Ipmipmn_api_coa_t *coa = ipcom_calloc(1, sizeof(*coa));
|
|
if (coa == IP_NULL)
|
|
return IP_NULL;
|
|
coa->type = type;
|
|
coa->addr = addr;
|
|
switch (type)
|
|
{
|
|
case IPMIPMN_ATTR_COA_CCOA:
|
|
coa->name = ipmip_util_strdup("CCoA(%s)", ipmip_ntop_inet(proc, addr));
|
|
coa->peer = IPMIPMN_ATTR_PEER_HOME_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_SKIP;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_TUNNEL;
|
|
|
|
/* Remove it from the obsolete list in case its there */
|
|
break;
|
|
case IPMIPMN_ATTR_COA_SCOA_TIA:
|
|
coa->params.tia = param->tia;
|
|
coa->name = ipmip_util_strdup("CCoA-TIA(%s/%s/%s)",
|
|
ipmip_ntop_inet(proc, addr),
|
|
ipmip_ntop_inet(proc, param->tia.ike_address),
|
|
ipmip_ntop_inet(proc, param->tia.local_address));
|
|
coa->peer = IPMIPMN_ATTR_PEER_HOME_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_SKIP;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_TUNNEL;
|
|
break;
|
|
case IPMIPMN_ATTR_COA_SCOA_PROTECTED:
|
|
coa->name = ipmip_util_strdup("CCoA-Prot(%s)", ipmip_ntop_inet(proc, addr));
|
|
coa->peer = IPMIPMN_ATTR_PEER_HOME_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_SKIP;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_TUNNEL;
|
|
break;
|
|
case IPMIPMN_ATTR_COA_SCOA_DEAD:
|
|
coa->params.tia = param->tia;
|
|
coa->name = ipmip_util_strdup("CCoA-Dead(%s/%s/%s)",
|
|
ipmip_ntop_inet(proc, addr),
|
|
ipmip_ntop_inet(proc, param->tia.ike_address),
|
|
ipmip_ntop_inet(proc, param->tia.local_address));
|
|
coa->peer = IPMIPMN_ATTR_PEER_HOME_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_SKIP;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_TUNNEL;
|
|
break;
|
|
case IPMIPMN_ATTR_COA_FA:
|
|
coa->name = ipmip_util_strdup("FA(%s)", ipmip_ntop_inet(proc, addr));
|
|
coa->peer = IPMIPMN_ATTR_PEER_FOREIGN_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_FA;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_FA;
|
|
IPMIP_TIMER_INIT(&coa->params.fa.timer);
|
|
break;
|
|
case IPMIPMN_ATTR_COA_FA_LLH:
|
|
coa->name = ipmip_util_strdup("FA-LLH(%s)", ipmip_ntop_inet(proc, addr));
|
|
coa->peer = IPMIPMN_ATTR_PEER_FOREIGN_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_FA;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_FA;
|
|
IPMIP_TIMER_INIT(&coa->params.fa.timer);
|
|
break;
|
|
case IPMIPMN_ATTR_COA_HA:
|
|
coa->name = ipmip_util_strdup("HA(%s)", ipmip_ntop_inet(proc, addr));
|
|
coa->peer = IPMIPMN_ATTR_PEER_HOME_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_HOME;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_HOME;
|
|
IPMIP_TIMER_INIT(&coa->params.ha.timer);
|
|
break;
|
|
default:
|
|
coa->name = ipmip_util_strdup("unknown(%s)", ipmip_ntop_inet(proc, addr));
|
|
coa->peer = IPMIPMN_ATTR_PEER_HOME_AGENT;
|
|
coa->route_ro = IPMIPMN_ROUTE_TYPE_BLACKHOLE;
|
|
coa->route_reverse = IPMIPMN_ROUTE_TYPE_BLACKHOLE;
|
|
break;
|
|
}
|
|
|
|
coa->output = (Ipmipmn_api_coa_output_t)ipmipmn_if_coa_output_send;
|
|
|
|
ifp->allocated++;
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"CoA '%s' added to interface '%s' (%d)",
|
|
coa->name,
|
|
ifp->iff.ipmip.ifname,
|
|
ifp->allocated));
|
|
|
|
ipmipmn_if_coa_reference_iflocked(data, proc, coa, IP_TRUE, "CoA Creation");
|
|
|
|
if (first)
|
|
ipcom_list_insert_first(&ifp->coa, &coa->next);
|
|
else
|
|
ipcom_list_insert_last(&ifp->coa, &coa->next);
|
|
return coa;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_get_iflocked
|
|
*===========================================================================
|
|
* Description: Retrieve a CoA of a specific type.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* addr - Address (may be 0)
|
|
* type - Type of CoA
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipmipmn_api_coa_t *
|
|
ipmipmn_if_coa_get_iflocked(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ip_u32 addr,
|
|
Ip_u32 type,
|
|
Ip_bool down)
|
|
{
|
|
Ipmipmn_api_coa_t *coa;
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
for (coa = IPCOM_LIST_FIRST(&ifp->coa); coa != IP_NULL; coa = IPCOM_LIST_NEXT(&coa->next))
|
|
{
|
|
if (coa->down && !down)
|
|
continue;
|
|
|
|
if (coa->type == type && (addr == 0 || coa->addr == addr))
|
|
break;
|
|
}
|
|
return coa;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_attached
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmipmn_if_attached(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
/* */
|
|
if (ifp->iff.ipmip.ifindex != 0)
|
|
{
|
|
(void)ipmip_if_resolve_lla(&data->api.ipmip4.ipmip, proc, &ifp->iff.ipmip);
|
|
|
|
/** JOIN **/
|
|
(void)ipmip4_pkt_icmp_join(&data->api.ipmip4, proc, ip_htonl(IP_INADDR_ALLHOSTS_GROUP), ifp->iff.ipmip.ifindex);
|
|
(void)ipmip4_pkt_icmp_join(&data->api.ipmip4, proc, ip_htonl(IP_INADDR_ALLRTRS_GROUP), ifp->iff.ipmip.ifindex);
|
|
}
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_acquire
|
|
*===========================================================================
|
|
* Description: Acquire an instantiation of a interface
|
|
* Parameters: data - Node context
|
|
* proc - Current process
|
|
* name - The name of the interface
|
|
* Returns: The pointer to the interface structure on success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmipmn_iff_t *
|
|
ipmipmn_if_acquire(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
const char *name,
|
|
Ipmipmn_iff_notify_t *notifier)
|
|
{
|
|
Ipmipmn_iff_t *ifp;
|
|
Ip_bool update = IP_FALSE;
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
ifp = ipmipmn_if_get_iflocked(data, proc, name);
|
|
|
|
/* */
|
|
if (ifp == IP_NULL)
|
|
{
|
|
/* Create the interface */
|
|
ifp = (Ipmipmn_iff_t*)ipmip4_if_alloc(&data->api.ipmip4,
|
|
proc,
|
|
sizeof(*ifp),
|
|
name,
|
|
0,
|
|
IPMIP_IF_TYPE_GENERIC,
|
|
IPMIPMN_IFF_IDENTITY_IFF,
|
|
(Ipmip_if_cleanup_t )ipmipmn_if_destroy);
|
|
|
|
/* Add */
|
|
if (ifp != IP_NULL)
|
|
{
|
|
Ip_u16 flags;
|
|
|
|
ifp->references++;
|
|
data->ifalloc++;
|
|
|
|
ipcom_list_init(&ifp->notifiers);
|
|
ipcom_list_init(&ifp->coa);
|
|
ipcom_list_insert_last(&data->ifhead, &ifp->iff.ipmip.next);
|
|
|
|
ifp->iff.ipmip.ifindex = ipcom_if_nametoindex(ifp->iff.ipmip.ifname);
|
|
|
|
if (ifp->iff.ipmip.ifindex)
|
|
ipmipmn_if_attached(data, proc, ifp);
|
|
if (!ifp->iff.ipmip.ifindex ||
|
|
!ipmip_if_get_flags(&data->api.ipmip4.ipmip, proc, &ifp->iff.ipmip, &flags) ||
|
|
!IP_BIT_ISSET(flags, IP_IFF_UP) ||
|
|
!IP_BIT_ISSET(flags, IP_IFF_RUNNING))
|
|
{
|
|
/* Not found; not running; not up */
|
|
ifp->link_down = IP_TRUE;
|
|
ifp->down = IP_TRUE;
|
|
}
|
|
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Interface '%s' added (%d)", ifp->iff.ipmip.ifname, data->ifalloc));
|
|
/* Populate interface */
|
|
update = IP_TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
/* */
|
|
if (ifp != IP_NULL && notifier != IP_NULL)
|
|
ipcom_list_insert_last(&ifp->notifiers, ¬ifier->if_next);
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
/* */
|
|
if (update)
|
|
ipmipmn_if_update_coa(data, proc);
|
|
|
|
return ifp;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_reference
|
|
*===========================================================================
|
|
* Description: Reference an interface pointer
|
|
* Parameters: data - Node context
|
|
* proc - Current process
|
|
* ifp - The interface
|
|
* Returns: The pointer to the interface structure on success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmipmn_iff_t *
|
|
ipmipmn_if_reference(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
ifp->references++;
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
return ifp;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_release
|
|
*===========================================================================
|
|
* Description: Release a previously acquired interface reference.
|
|
* Parameters: data - Context
|
|
* proc - The process
|
|
* iff - Interface pointer.
|
|
* Returns: IP_TRUE if the interface was destroyed; IP_FALSE otherwise.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipmipmn_if_release(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *iff,
|
|
Ipmipmn_iff_notify_t *notifier)
|
|
{
|
|
Ip_bool ret;
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
if (notifier)
|
|
{
|
|
ipcom_list_remove(¬ifier->if_next);
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, ¬ifier->timer);
|
|
}
|
|
|
|
ret = ipmipmn_if_put_iflocked(data, proc, iff);
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_update_coa
|
|
*===========================================================================
|
|
* Description: Retrieve a secure address
|
|
* Parameters: mn - Mobile node data
|
|
* proc - Process
|
|
* ifname - The interface name
|
|
* addr - The address
|
|
* netmask - The netmask
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipmipmn_if_update_coa(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc)
|
|
{
|
|
/**/
|
|
Ip_u32 timestamp;
|
|
Ipmipmn_iff_t *ifp;
|
|
Ipmipmn_api_coa_t *coa;
|
|
Ipmipmn_api_coa_params_t cparam;
|
|
Ipmip_buffer_t reply;
|
|
int ret;
|
|
|
|
ipcom_memset(&cparam, 0, sizeof(cparam));
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
/**/
|
|
timestamp = data->ifstamp++;
|
|
|
|
for (ifp = IPCOM_LIST_FIRST(&data->ifhead); ifp != IP_NULL; ifp = IPCOM_LIST_NEXT(&ifp->iff.ipmip.next))
|
|
{
|
|
Ip_u16 flags;
|
|
Ip_u32 ifindex;
|
|
|
|
if ((ifindex = ipcom_if_nametoindex(ifp->iff.ipmip.ifname)) == 0 ||
|
|
!ipmip_if_get_flags(&data->api.ipmip4.ipmip, proc, &ifp->iff.ipmip, &flags) ||
|
|
!IP_BIT_ISSET(flags, IP_IFF_UP) ||
|
|
!IP_BIT_ISSET(flags, IP_IFF_RUNNING))
|
|
{
|
|
if (!ifp->link_down)
|
|
{
|
|
ifp->link_down = IP_TRUE;
|
|
if (!ifp->down)
|
|
{
|
|
ifp->sync_count++;
|
|
ifp->down = IP_TRUE;
|
|
ifp->timestamp = timestamp;
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Interface %s is brought down",
|
|
ifp->iff.ipmip.ifname));
|
|
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ifp->link_down)
|
|
{
|
|
ifp->link_down = IP_FALSE;
|
|
if (ifp->down && !ifp->admin_down)
|
|
{
|
|
ifp->down = IP_FALSE;
|
|
ifp->timestamp = timestamp;
|
|
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Interface %s is brought up",
|
|
ifp->iff.ipmip.ifname));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update IFINDEX */
|
|
if (ifindex != ifp->iff.ipmip.ifindex)
|
|
{
|
|
ifp->timestamp = timestamp;
|
|
ifp->iff.ipmip.ifindex = ifindex;
|
|
}
|
|
|
|
if (!ifp->link_down)
|
|
ipmipmn_if_attached(data, proc, ifp);
|
|
}
|
|
|
|
ipmip_buffer_init(&reply);
|
|
if ((ret = ipmip_netlink_inX_addr_dump(&data->api.ipmip4.ipmip, proc, IP_AF_INET, &reply)) < 0)
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Unable to dump INET addresses error value %d", -ret));
|
|
}
|
|
else
|
|
{
|
|
struct Ip_nlmsghdr *nlh = IPMIP_BUFFER_PTR(&reply);
|
|
Ip_size_t nlh_size = IPMIP_BUFFER_SIZE(&reply);
|
|
|
|
/* */
|
|
while (IP_NLMSG_OK(nlh, nlh_size))
|
|
{
|
|
/**/
|
|
if (nlh->nlmsg_type == IP_RTM_NEWADDR)
|
|
{
|
|
struct Ip_ifaddrmsg *ifa = IP_NLMSG_DATA(nlh);
|
|
struct Ip_rtattr *ifap[IP_IFA_MAX + 1];
|
|
|
|
ifp = ipmipmn_if_getbyindex_iflocked(data, proc, ifa->ifa_index);
|
|
|
|
/* Don't have */
|
|
if (ifp != IP_NULL)
|
|
{
|
|
|
|
/* Parse */
|
|
ipmip_netlink_nlmsghdr_rta_parse(IP_IFA_MAX + 1,
|
|
IP_IFA_RTA(ifa),
|
|
IP_IFA_PAYLOAD(nlh),
|
|
ifap);
|
|
|
|
if (ifap[IP_IFA_LOCAL])
|
|
{
|
|
Ip_u32 addr = IP_GET_32ON8(IP_RTA_DATA(ifap[IP_IFA_LOCAL]));
|
|
int type = ipmipmn_if_coa_type(data, proc, &reply, addr, &cparam);
|
|
|
|
switch (type)
|
|
{
|
|
case IPMIPMN_ATTR_COA_SCOA_PROTECTED:
|
|
case IPMIPMN_ATTR_COA_SCOA_TIA:
|
|
case IPMIPMN_ATTR_COA_SCOA_DEAD:
|
|
case IPMIPMN_ATTR_COA_CCOA:
|
|
coa = ipmipmn_if_coa_get_iflocked(data, proc, ifp, addr, type, IP_TRUE);
|
|
if (coa)
|
|
{
|
|
/* Timestamp it */
|
|
coa->timestamp = timestamp;
|
|
|
|
/* Back in buisiness */
|
|
if (coa->down)
|
|
{
|
|
coa->down = IP_FALSE;
|
|
ifp->timestamp = timestamp;
|
|
|
|
/* Return the sysref */
|
|
ipmipmn_if_coa_reference_iflocked(data, proc, coa, IP_TRUE, "CoA Reappeared");
|
|
}
|
|
|
|
ipmipmn_if_coa_relink_iflocked(data, proc, ifp, coa, IP_FALSE);
|
|
}
|
|
else
|
|
{
|
|
if (type == IPMIPMN_ATTR_COA_CCOA)
|
|
{
|
|
Ipmipmn_api_coa_t *scoa;
|
|
|
|
/* Detached TIA */
|
|
if ((scoa = ipmipmn_if_coa_get_iflocked(data, proc, ifp, addr, IPMIPMN_ATTR_COA_SCOA_DEAD, IP_FALSE)) != IP_NULL)
|
|
{
|
|
scoa->timestamp = timestamp;
|
|
break;
|
|
}
|
|
else if ((scoa = ipmipmn_if_coa_get_iflocked(data, proc, ifp, addr, IPMIPMN_ATTR_COA_SCOA_TIA, IP_FALSE)) != IP_NULL)
|
|
{
|
|
coa = ipmipmn_if_coa_new_iflocked(data, proc, ifp, addr, IPMIPMN_ATTR_COA_SCOA_DEAD, IP_FALSE, &scoa->params);
|
|
coa->timestamp = timestamp;
|
|
coa->params.tia.mobiked = IP_FALSE;
|
|
ifp->timestamp = timestamp;
|
|
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, scoa, IP_TRUE, IP_TRUE, "Address type changed");
|
|
break;
|
|
}
|
|
}
|
|
else if (type == IPMIPMN_ATTR_COA_SCOA_TIA)
|
|
{
|
|
Ipmipmn_api_coa_t *scoa;
|
|
if ((scoa = ipmipmn_if_coa_get_iflocked(data, proc, ifp, addr, IPMIPMN_ATTR_COA_SCOA_DEAD, IP_FALSE)) != IP_NULL)
|
|
{
|
|
if (scoa->params.tia.mobiked)
|
|
cparam.tia.mobiked = IP_TRUE;
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, scoa, IP_TRUE, IP_TRUE, "CCoA-TIA reappered");
|
|
}
|
|
}
|
|
|
|
/* Add it */
|
|
coa = ipmipmn_if_coa_new_iflocked(data, proc, ifp, addr, type, IP_FALSE, &cparam);
|
|
coa->timestamp = timestamp;
|
|
ifp->timestamp = timestamp;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
ipmipmn_if_put_iflocked(data, proc, ifp);
|
|
}
|
|
|
|
}
|
|
|
|
/**/
|
|
nlh = IP_NLMSG_NEXT(nlh, nlh_size);
|
|
}
|
|
|
|
}
|
|
|
|
ipmip_buffer_release(&reply);
|
|
|
|
/* Remove any COA's not holding the correct timestamp */
|
|
/* Go through the interface list */
|
|
for (ifp = IPCOM_LIST_FIRST(&data->ifhead); ifp != IP_NULL; ifp = IPCOM_LIST_NEXT(&ifp->iff.ipmip.next))
|
|
{
|
|
for (coa = IPCOM_LIST_FIRST(&ifp->coa); coa != IP_NULL;)
|
|
{
|
|
Ipmipmn_api_coa_t *ncoa = IPCOM_LIST_NEXT(&coa->next);
|
|
|
|
/* Dont touch external CoA's */
|
|
if (coa->peer == IPMIPMN_ATTR_PEER_FOREIGN_AGENT)
|
|
{
|
|
if (ifp->down && !coa->down)
|
|
{
|
|
/**/
|
|
coa->down = IP_TRUE;
|
|
|
|
/* Sysref? */
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, coa, IP_FALSE, IP_TRUE, "Interface down");
|
|
|
|
/* Flag the interface as being timestamped */
|
|
ifp->timestamp = timestamp;
|
|
}
|
|
}
|
|
else if (coa->type != IPMIPMN_ATTR_COA_HA)
|
|
{
|
|
/* No longer around? */
|
|
if (coa->timestamp != timestamp)
|
|
{
|
|
coa->down = IP_TRUE;
|
|
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, coa, IP_TRUE, IP_TRUE, "CoA Disappeared");
|
|
|
|
/* Flag the interface as being timestamped */
|
|
ifp->timestamp = timestamp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ifp->down && !coa->down)
|
|
{
|
|
coa->down = IP_TRUE;
|
|
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, coa, IP_TRUE, IP_TRUE, "Interface down");
|
|
|
|
/* Flag the interface as being timestamped */
|
|
ifp->timestamp = timestamp;
|
|
}
|
|
else if (!ifp->down && ifp->timestamp == timestamp)
|
|
{
|
|
/* Something on this interface has changed */
|
|
if (coa->params.ha.verify == IPMIPMN_IFF_COA_HA_VERIFY_NONE)
|
|
coa->params.ha.verify = IPMIPMN_IFF_COA_HA_VERIFY_REQUEST;
|
|
}
|
|
}
|
|
|
|
coa = ncoa;
|
|
}
|
|
}
|
|
|
|
/* Notify on all timestamped interfaces */
|
|
for (ifp = IPCOM_LIST_FIRST(&data->ifhead); ifp != IP_NULL; ifp = IPCOM_LIST_NEXT(&ifp->iff.ipmip.next))
|
|
{
|
|
if (ifp->timestamp == timestamp)
|
|
ipmipmn_if_notify_iflocked(data, proc, ifp);
|
|
}
|
|
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_get
|
|
*===========================================================================
|
|
* Description: Retrieve a CoA of a specific type.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* addr - Address (may be 0)
|
|
* type - Type of CoA
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmipmn_api_coa_t *
|
|
ipmipmn_if_coa_get(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ip_u32 addr,
|
|
Ip_u32 type,
|
|
const char *reason)
|
|
{
|
|
Ipmipmn_api_coa_t *coa;
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
coa = ipmipmn_if_coa_get_iflocked(data, proc, ifp, addr, type, IP_FALSE);
|
|
if (coa)
|
|
ipmipmn_if_coa_reference_iflocked(data, proc, coa, IP_FALSE, reason);
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return coa;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_put
|
|
*===========================================================================
|
|
* Description: Return a previously retrieved CoA
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* coa - CoA
|
|
* Returns: IP_TRUE if the CoA was deleted.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipmipmn_if_coa_put(Ipmipmn_context_t *data,
|
|
Ipmip_proc_t *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *coa,
|
|
const char *reason)
|
|
{
|
|
Ip_bool dele;
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
dele = ipmipmn_if_coa_put_iflocked(data, proc, ifp, coa, IP_FALSE, IP_FALSE, reason);
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return dele;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_findbyindex
|
|
*===========================================================================
|
|
* Description: Find an existing interface by locating its index.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifindex - Interface index.
|
|
* Returns: A referenced handle to the interface. Must be returned by
|
|
* release.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmipmn_iff_t *
|
|
ipmipmn_if_findbyindex(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
int ifindex)
|
|
{
|
|
Ipmipmn_iff_t *ifp;
|
|
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
/* Go through the interface list */
|
|
ifp = ipmipmn_if_getbyindex_iflocked(data, proc, ifindex);
|
|
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return ifp;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_fa_adv
|
|
*===========================================================================
|
|
* Description: Process a foreign agent advertisement and update any
|
|
* foreign agent values.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* pbuf - Packet buffer.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmipmn_if_fa_adv(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_pktbuf_t *pbuf)
|
|
{
|
|
Ipmipmn_api_coa_t *fa;
|
|
Ip_bool change = IP_FALSE;
|
|
Ip_bool unreliable = IP_FALSE;
|
|
Ip_bool relinked = IP_FALSE;
|
|
int type = pbuf->api.ipmip4.ext.icmp.lla.found? IPMIPMN_ATTR_COA_FA_LLH : IPMIPMN_ATTR_COA_FA;
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
/* Find it it? */
|
|
fa = ipmipmn_if_coa_get_iflocked(data, proc, pbuf->api.iff.priv, pbuf->api.advinfo.coa, type, IP_TRUE);
|
|
if (fa != IP_NULL)
|
|
{
|
|
/* Check if FA rebooted */
|
|
if (pbuf->api.advinfo.adv_seq < fa->params.fa.adv_seq && pbuf->api.advinfo.adv_seq < 256)
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Foreign Agent '%s' rebooted (seq=%d, oldseq=%d)",
|
|
ipmip_ntop_inet(proc, fa->addr),
|
|
(int)pbuf->api.advinfo.adv_seq,
|
|
fa->params.fa.adv_seq));
|
|
|
|
fa->params.fa.revoked = IP_TRUE;
|
|
change = IP_TRUE;
|
|
ipmipmn_if_coa_put_iflocked(data, proc, pbuf->api.iff.priv, fa, IP_TRUE, IP_TRUE, "FA Rebooted");
|
|
fa = IP_NULL;
|
|
goto create;
|
|
}
|
|
|
|
if (IP_BIT_ISSET(pbuf->api.advinfo.flags, IPMIP4_ICMP_ADVEXT_FLAG_BUSY))
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Foreign Agent '%s' reported as busy",
|
|
ipmip_ntop_inet(proc, fa->addr)));
|
|
change = IP_TRUE;
|
|
fa->params.fa.revoked = IP_TRUE;
|
|
ipmipmn_if_coa_put_iflocked(data, proc, pbuf->api.iff.priv, fa, IP_TRUE, IP_TRUE, "FA Busy");
|
|
fa = IP_NULL;
|
|
goto done_out;
|
|
}
|
|
|
|
|
|
/* Seen again? */
|
|
if (fa->down)
|
|
{
|
|
fa->down = IP_FALSE;
|
|
fa->unreliable = IP_FALSE;
|
|
change = IP_TRUE;
|
|
relinked = IP_TRUE;
|
|
|
|
ipmipmn_if_coa_reference_iflocked(data, proc, fa, IP_TRUE, "Previously 'down' FA was advertised");
|
|
|
|
/* Relink first */
|
|
ipmipmn_if_coa_relink_iflocked(data, proc, pbuf->api.iff.priv, fa, IP_TRUE);
|
|
}
|
|
|
|
/* Detached? */
|
|
if (fa->unreliable)
|
|
{
|
|
fa->unreliable = IP_FALSE;
|
|
unreliable = IP_TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
create:
|
|
if (IP_BIT_ISSET(pbuf->api.advinfo.flags, IPMIP4_ICMP_ADVEXT_FLAG_BUSY))
|
|
goto done_out;
|
|
|
|
relinked = IP_TRUE;
|
|
fa = ipmipmn_if_coa_new_iflocked(data, proc, pbuf->api.iff.priv, pbuf->api.advinfo.coa, type, IP_TRUE, IP_NULL);
|
|
}
|
|
|
|
if (fa != IP_NULL)
|
|
{
|
|
/* Store the flags */
|
|
fa->params.fa.adv_flags = pbuf->api.advinfo.flags;
|
|
|
|
/* Update params */
|
|
if (ipmip_lladdr_cmp(fa->params.fa.lladdr, pbuf->api.ipmip4.ipmip.srcinfo.lladdr) == IP_FALSE)
|
|
{
|
|
change = IP_TRUE;
|
|
/* We're using this one instead */
|
|
ipmip_util_dup(&fa->params.fa.lladdr,
|
|
pbuf->api.ipmip4.ipmip.srcinfo.lladdr,
|
|
pbuf->api.ipmip4.ipmip.srcinfo.lladdr->len);
|
|
}
|
|
|
|
/* LLH CoA */
|
|
if (pbuf->api.ipmip4.ext.icmp.lla.found > 0)
|
|
{
|
|
Ipmip_lladdr_t *lladdr;
|
|
|
|
/* Relink first */
|
|
ipmipmn_if_coa_relink_iflocked(data, proc, pbuf->api.iff.priv, fa, IP_TRUE);
|
|
change = IP_TRUE;
|
|
relinked = IP_TRUE;
|
|
|
|
|
|
lladdr = ipmip4_lla_llh_convert_lla_to_lladdr(IP_NULL, (Ipmip4_icmp_lla_ext_t *)pbuf->api.ipmip4.ext.icmp.lla.ext[0]);
|
|
|
|
if (ipmip_lladdr_cmp(fa->params.fa.lladdr_llh, lladdr) == IP_FALSE)
|
|
{
|
|
/* We're using this one instead */
|
|
ipcom_free(fa->params.fa.lladdr_llh);
|
|
fa->params.fa.lladdr_llh = lladdr;
|
|
}
|
|
else
|
|
{
|
|
ipcom_free(lladdr);
|
|
}
|
|
}
|
|
|
|
/* Look for FA challenge extension */
|
|
if (fa->params.fa.challenge != IP_NULL)
|
|
{
|
|
ipcom_free(fa->params.fa.challenge);
|
|
fa->params.fa.challenge = IP_NULL;
|
|
}
|
|
|
|
if (pbuf->api.ipmip4.ext.icmp.challenge)
|
|
{
|
|
/* Found challenge extension */
|
|
if (IPMIP4_MSGEXT_SHDR_EXT_SIZE(pbuf->api.ipmip4.ext.icmp.challenge) <= IPMIPMN_MAX_CHALLENGE_SIZE)
|
|
{
|
|
/* Save FA challenge */
|
|
fa->params.fa.challenge = ipmip4_msgext_shdr_dup(pbuf->api.ipmip4.ext.icmp.challenge);
|
|
if(IP_NULL == fa->params.fa.challenge)
|
|
goto done_out;
|
|
|
|
fa->params.fa.challenge->shdr.type = IPMIP4_EXT_TYPE_AGENT_ADV_CHALLENGE;
|
|
change = IP_TRUE;
|
|
}
|
|
else
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Foreign Agent '%s' included challenge with a longer than supporter maximum size",
|
|
ipmip_ntop_inet(proc, fa->addr)));
|
|
}
|
|
}
|
|
|
|
/* Move us to be the FIRST foreign agent */
|
|
if (!relinked)
|
|
{
|
|
Ipmipmn_api_coa_t *coa;
|
|
Ipmipmn_api_coa_t *ffa = IP_NULL;
|
|
for (coa = IPCOM_LIST_PREV(&fa->next); coa != IP_NULL; coa = IPCOM_LIST_PREV(&coa->next))
|
|
{
|
|
/**/
|
|
if (coa->type == IPMIPMN_ATTR_COA_FA)
|
|
ffa = coa;
|
|
}
|
|
|
|
|
|
/* Found a previous entry? */
|
|
if (ffa != IP_NULL)
|
|
{
|
|
ipcom_list_remove(&fa->next);
|
|
ipcom_list_insert_before(&ffa->next, &fa->next);
|
|
change = IP_TRUE;
|
|
}
|
|
}
|
|
|
|
/* Update */
|
|
fa->params.fa.adv_seq = pbuf->api.advinfo.adv_seq;
|
|
if ((pbuf->api.advinfo.lifetime == 0 || fa->params.fa.lifetime == 0) && pbuf->api.advinfo.lifetime != fa->params.fa.lifetime)
|
|
change = IP_TRUE;
|
|
fa->params.fa.lifetime = pbuf->api.advinfo.lifetime;
|
|
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, &fa->params.fa.timer);
|
|
ipmip_timer_request(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
&fa->params.fa.timer,
|
|
data->iflock,
|
|
(Ipmip_timer_func_t)ipmipmn_if_agent_timeout_iflocked,
|
|
fa,
|
|
pbuf->api.iff.priv,
|
|
fa->params.fa.lifetime * 1000);
|
|
}
|
|
|
|
done_out:
|
|
|
|
#if 1
|
|
if (unreliable && fa != IP_NULL)
|
|
{
|
|
Ipmipmn_api_coa_t *coa;
|
|
|
|
/* Go through and locate and Home Agents located _AFTER_ the foreign agent, have we done
|
|
* a 'silent' move? */
|
|
for (coa = IPCOM_LIST_PREV(&fa->next); coa != IP_NULL; coa = IPCOM_LIST_PREV(&coa->next))
|
|
{
|
|
if (coa->down)
|
|
continue;
|
|
|
|
/**/
|
|
if (coa->type == IPMIPMN_ATTR_COA_HA && coa->params.ha.verify == IPMIPMN_IFF_COA_HA_VERIFY_NONE)
|
|
{
|
|
/* Need to do a directed solicitation on this HA; verify that
|
|
* it's still available */
|
|
coa->params.ha.verify = IPMIPMN_IFF_COA_HA_VERIFY_REQUEST;
|
|
change = IP_TRUE;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**/
|
|
if (change)
|
|
{
|
|
#if 1
|
|
if (relinked && fa != IP_NULL)
|
|
{
|
|
Ipmipmn_api_coa_t *coa;
|
|
|
|
/* Go through and locate and Home Agents located _AFTER_ the foreign agent, have we done
|
|
* a 'silent' move? */
|
|
for (coa = IPCOM_LIST_NEXT(&fa->next); coa != IP_NULL; coa = IPCOM_LIST_NEXT(&coa->next))
|
|
{
|
|
if (coa->down)
|
|
continue;
|
|
|
|
/**/
|
|
if (coa->type == IPMIPMN_ATTR_COA_HA && coa->params.ha.verify == IPMIPMN_IFF_COA_HA_VERIFY_NONE)
|
|
{
|
|
/* Need to do a directed solicitation on this HA; verify that
|
|
* it's still available */
|
|
coa->params.ha.verify = IPMIPMN_IFF_COA_HA_VERIFY_REQUEST;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ipmipmn_if_notify_iflocked(data, proc, pbuf->api.iff.priv);
|
|
}
|
|
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_fa_arp
|
|
*===========================================================================
|
|
* Description: Process an ARP reply and update any
|
|
* foreign agent values.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* pbuf - Packet buffer.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmipmn_if_fa_arp(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_pktbuf_t *pbuf)
|
|
{
|
|
Ipmipmn_api_coa_t *fa;
|
|
Ip_bool change = IP_FALSE;
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
/* Find it it? */
|
|
fa = ipmipmn_if_coa_get_iflocked(data, proc, pbuf->api.iff.priv, pbuf->api.advinfo.coa, IPMIPMN_ATTR_COA_FA, IP_TRUE);
|
|
if (fa != IP_NULL)
|
|
{
|
|
/* Update params */
|
|
if (ipmip_lladdr_cmp(fa->params.fa.lladdr, pbuf->api.ipmip4.ipmip.srcinfo.lladdr) == IP_FALSE)
|
|
{
|
|
change = IP_TRUE;
|
|
/* We're using this one instead */
|
|
ipmip_util_dup(&fa->params.fa.lladdr,
|
|
pbuf->api.ipmip4.ipmip.srcinfo.lladdr,
|
|
pbuf->api.ipmip4.ipmip.srcinfo.lladdr->len);
|
|
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Foreign Agent '%s' changed LLA to '%s', Low Latency in effect?",
|
|
ipmip_ntop_inet(proc, fa->addr),
|
|
ipmip_ntop_lladdr(proc, fa->params.fa.lladdr)));
|
|
}
|
|
}
|
|
|
|
/**/
|
|
if (change)
|
|
ipmipmn_if_notify_iflocked(data, proc, pbuf->api.iff.priv);
|
|
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_ha_adv_verify
|
|
*===========================================================================
|
|
* Description: Do home agent verification; if there's been a 'silent' roam
|
|
* we need to discover it.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - The interface
|
|
* ha - The home agent.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipmipmn_if_ha_adv_verify(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *ha)
|
|
{
|
|
Ip_bool verify;
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
verify = ha->params.ha.verify == IPMIPMN_IFF_COA_HA_VERIFY_REQUEST;
|
|
if (verify)
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Verifying Home Agent '%s' on interface %s due to foreign agent advertisement",
|
|
ha->name,
|
|
ifp->iff.ipmip.ifname));
|
|
|
|
/* Reschedule timeout */
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, &ha->params.ha.timer);
|
|
ipmip_timer_request(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
&ha->params.ha.timer,
|
|
data->iflock,
|
|
(Ipmip_timer_func_t)ipmipmn_if_agent_timeout_iflocked,
|
|
ha,
|
|
ifp,
|
|
2000);
|
|
ha->params.ha.verify = IPMIPMN_IFF_COA_HA_VERIFY_PENDING;
|
|
}
|
|
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return verify;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_ha_adv
|
|
*===========================================================================
|
|
* Description: Process a home agent advertisement and update any
|
|
* home agent values.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* pbuf - Packet buffer.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmipmn_if_ha_adv(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_pktbuf_t *pbuf)
|
|
{
|
|
Ipmipmn_api_coa_t *ha;
|
|
Ip_bool change = IP_FALSE;
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
/* Find it it? */
|
|
ha = ipmipmn_if_coa_get_iflocked(data, proc, pbuf->api.iff.priv, pbuf->api.ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr, IPMIPMN_ATTR_COA_HA, IP_FALSE);
|
|
if (ha == IP_NULL)
|
|
{
|
|
ha = ipmipmn_if_coa_new_iflocked(data, proc, pbuf->api.iff.priv, pbuf->api.ipmip4.ipmip.srcinfo.src->sin.sin_addr.s_addr, IPMIPMN_ATTR_COA_HA, IP_TRUE, IP_NULL);
|
|
if (ha != IP_NULL)
|
|
change = IP_TRUE;
|
|
}
|
|
|
|
/**/
|
|
if (ha != IP_NULL)
|
|
{
|
|
if (change)
|
|
{
|
|
Ipmipmn_api_coa_t *coa;
|
|
|
|
/* Go through and locate and Home Agents located _AFTER_ the foreign agent, have we done
|
|
* a 'silent' move? */
|
|
for (coa = IPCOM_LIST_NEXT(&ha->next); coa != IP_NULL; coa = IPCOM_LIST_NEXT(&coa->next))
|
|
{
|
|
if (coa->down)
|
|
continue;
|
|
|
|
/**/
|
|
if (coa->type == IPMIPMN_ATTR_COA_FA)
|
|
{
|
|
/* Need to do a directed solicitation on this HA; verify that
|
|
* it's still available */
|
|
coa->unreliable = IP_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Update params */
|
|
if (ipmip_lladdr_cmp(ha->params.ha.lladdr, pbuf->api.ipmip4.ipmip.srcinfo.lladdr) == IP_FALSE)
|
|
{
|
|
change = IP_TRUE;
|
|
/* We're using this one instead */
|
|
ipmip_util_dup(&ha->params.ha.lladdr,
|
|
pbuf->api.ipmip4.ipmip.srcinfo.lladdr,
|
|
pbuf->api.ipmip4.ipmip.srcinfo.lladdr->len);
|
|
}
|
|
|
|
/* Verified */
|
|
ha->params.ha.verify = IPMIPMN_IFF_COA_HA_VERIFY_NONE;
|
|
|
|
/* Always relink to first in list when seen */
|
|
ipmipmn_if_coa_relink_iflocked(data, proc, pbuf->api.iff.priv, ha, IP_TRUE);
|
|
|
|
/* Update lifetime */
|
|
ha->params.ha.lifetime = pbuf->api.advinfo.lifetime;
|
|
|
|
/* Reschedule timeout */
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, &ha->params.ha.timer);
|
|
ipmip_timer_request(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
&ha->params.ha.timer,
|
|
data->iflock,
|
|
(Ipmip_timer_func_t)ipmipmn_if_agent_timeout_iflocked,
|
|
ha,
|
|
pbuf->api.iff.priv,
|
|
ha->params.ha.lifetime * 1000);
|
|
}
|
|
|
|
/**/
|
|
if (change)
|
|
ipmipmn_if_notify_iflocked(data, proc, pbuf->api.iff.priv);
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_fa_llh
|
|
*===========================================================================
|
|
* Description: Turn a LLH coa into a usable directly connected one.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - The interface
|
|
* llh_coa - LLH CoA
|
|
* Returns: A new freshly allocated direct CoA
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmipmn_api_coa_t *
|
|
ipmipmn_if_coa_fa_llh(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *llh_coa)
|
|
{
|
|
Ipmipmn_api_coa_t *fa;
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
/* Find it it? */
|
|
fa = ipmipmn_if_coa_get_iflocked(data, proc, ifp, llh_coa->addr, IPMIPMN_ATTR_COA_FA, IP_TRUE);
|
|
if (fa == IP_NULL || fa->down)
|
|
{
|
|
if (fa == IP_NULL)
|
|
fa = ipmipmn_if_coa_new_iflocked(data, proc, ifp, llh_coa->addr, IPMIPMN_ATTR_COA_FA, IP_TRUE, IP_NULL);
|
|
|
|
if (fa != IP_NULL)
|
|
{
|
|
/* Update */
|
|
fa->params.fa.adv_seq = llh_coa->params.fa.adv_seq;
|
|
fa->params.fa.adv_flags = llh_coa->params.fa.adv_flags;
|
|
fa->params.fa.lifetime = llh_coa->params.fa.lifetime;
|
|
|
|
/* We're using this one instead */
|
|
ipmip_util_dup(&fa->params.fa.lladdr,
|
|
llh_coa->params.fa.lladdr_llh,
|
|
llh_coa->params.fa.lladdr_llh->len);
|
|
|
|
ipmip_timer_cancel(&data->api.ipmip4.ipmip, proc, &fa->params.fa.timer);
|
|
ipmip_timer_request(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
&fa->params.fa.timer,
|
|
data->iflock,
|
|
(Ipmip_timer_func_t)ipmipmn_if_agent_timeout_iflocked,
|
|
fa,
|
|
ifp,
|
|
fa->params.fa.lifetime * 1000);
|
|
|
|
if (fa->down)
|
|
{
|
|
fa->down = IP_FALSE;
|
|
ipmipmn_if_coa_reference_iflocked(data, proc, fa, IP_TRUE, "LLH Completed");
|
|
ipmipmn_if_coa_relink_iflocked(data, proc, ifp, fa, IP_TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fa)
|
|
{
|
|
ipmipmn_if_coa_reference_iflocked(data, proc, fa, IP_FALSE, "LLH Done");
|
|
ipmipmn_if_coa_put_iflocked(data, proc, ifp, llh_coa, IP_FALSE, IP_FALSE, "LLH Done");
|
|
}
|
|
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return fa;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_admin_down
|
|
*===========================================================================
|
|
* Description: Bring an interface administratively down.
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - The interface
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmipmn_if_admin_down(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
if (!ifp->admin_down)
|
|
{
|
|
ifp->admin_down = IP_TRUE;
|
|
ifp->references++;
|
|
ipmipmn_if_ifstate_iflocked(data, proc, ifp);
|
|
}
|
|
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_admin_up
|
|
*===========================================================================
|
|
* Description: Bring an interface administratively up
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* ifp - The interface
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmipmn_if_admin_up(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp)
|
|
{
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
if (ifp->admin_down)
|
|
{
|
|
ifp->admin_down = IP_FALSE;
|
|
ipmipmn_if_put_iflocked(data, proc, ifp);
|
|
ipmipmn_if_ifstate_iflocked(data, proc, ifp);
|
|
}
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_reference
|
|
*===========================================================================
|
|
* Description: Reference the CoA
|
|
* Parameters: data - Context
|
|
* proc - Process
|
|
* coa - CoA
|
|
* Returns: The CoA
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmipmn_api_coa_t *
|
|
ipmipmn_if_coa_reference(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_api_coa_t *coa,
|
|
const char *reason)
|
|
{
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
ipmipmn_if_coa_reference_iflocked(data, proc, coa, IP_FALSE, reason);
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
return coa;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_ike_reconfigure
|
|
*===========================================================================
|
|
* Description: Request a re-configuration of IKE if required.
|
|
* Parameters: data - The context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* coa - Care of Address.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipmipmn_if_coa_ike_reconfigure(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *coa)
|
|
{
|
|
#ifdef IPIPSEC2
|
|
Ip_bool reconfigure = IP_FALSE;
|
|
IPMIP_UNUSED_PARAMETER(ifp);
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
if (coa->type == IPMIPMN_ATTR_COA_CCOA)
|
|
{
|
|
if (coa->params.ccoa.ike_reconfigure == IP_FALSE)
|
|
{
|
|
reconfigure = IP_TRUE;
|
|
coa->params.ccoa.ike_reconfigure = IP_TRUE;
|
|
}
|
|
}
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
/* */
|
|
if (reconfigure)
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Reconfigure IKE due to new primary CoA"));
|
|
ipcom_ipd_send("ipike", IPCOM_IPD_MSGTYPE_RECONFIGURE);
|
|
return IP_TRUE;
|
|
}
|
|
|
|
#else
|
|
IPMIP_UNUSED_PARAMETER(ifp);
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(coa);
|
|
#endif
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipmn_if_coa_ike_mobility
|
|
*===========================================================================
|
|
* Description: Request an IKE mobility movement
|
|
* Parameters: data - The context
|
|
* proc - Process
|
|
* ifp - Interface
|
|
* coa - Care of Address.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_bool
|
|
ipmipmn_if_coa_ike_mobility(struct Ipmipmn_context *data,
|
|
struct Ipmip_proc *proc,
|
|
Ipmipmn_iff_t *ifp,
|
|
Ipmipmn_api_coa_t *coa)
|
|
{
|
|
#ifdef IPIKE
|
|
Ip_u32 endpoints[4];
|
|
Ip_u32 endindex = 0;
|
|
unsigned int i;
|
|
unsigned int p;
|
|
Ip_bool pending = IP_FALSE;
|
|
|
|
IPMIP_UNUSED_PARAMETER(ifp);
|
|
|
|
ipmip_timer_lock_acquire(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
if (coa->type == IPMIPMN_ATTR_COA_CCOA)
|
|
{
|
|
struct Ip_ifaddrs *ifaddrs = IP_NULL;
|
|
Ipmipmn_api_coa_t *scoa;
|
|
|
|
/* Get interface addresses */
|
|
ipcom_getifaddrs(&ifaddrs);
|
|
|
|
/**/
|
|
for (scoa = IPCOM_LIST_FIRST(&ifp->coa); endindex < 4 && scoa != IP_NULL; scoa = IPCOM_LIST_NEXT(&scoa->next))
|
|
{
|
|
Ipmip_buffer_t reply;
|
|
|
|
if (scoa->type != IPMIPMN_ATTR_COA_SCOA_DEAD)
|
|
continue;
|
|
|
|
pending = IP_TRUE;
|
|
|
|
if (scoa->params.tia.mobiked)
|
|
continue;
|
|
|
|
ipmip_buffer_init(&reply);
|
|
if (ipmip4_netlink_route_validate(&data->api.ipmip4, proc, ifp->iff.ipmip.ifindex, scoa->params.tia.ike_address, &reply) < 0)
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Postponing mobike request, since %s is not yet routable",
|
|
ipmip_ntop_inet(proc, scoa->params.tia.ike_address)));
|
|
continue;
|
|
}
|
|
ipmip_buffer_release(&reply);
|
|
|
|
#if 0
|
|
if (!ipmip4_usr_route_validate(&data->api.ipmip4, proc, &ifp->iff, 0, scoa->params.tia.ike_address))
|
|
{
|
|
IPMIP4_EVENT_IF(INFO, proc,
|
|
ipmip_log_event_add(&data->api.ipmip4.ipmip,
|
|
proc,
|
|
"Postponing mobike request, since %s is not yet routable",
|
|
ipmip_ntop_inet(proc, scoa->params.tia.ike_address)));
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
for (p = 0; p < endindex; p++)
|
|
{
|
|
if (endpoints[p] == scoa->params.tia.local_address)
|
|
break;
|
|
}
|
|
|
|
/**/
|
|
scoa->params.tia.mobiked = IP_TRUE;
|
|
if (p == endindex)
|
|
endpoints[endindex++] = scoa->params.tia.local_address;
|
|
}
|
|
|
|
/* Free the interface addresses */
|
|
ipcom_freeifaddrs(ifaddrs);
|
|
}
|
|
ipmip_timer_lock_release(&data->api.ipmip4.ipmip, proc, data->iflock);
|
|
|
|
/* Move the IKE endpoints */
|
|
for (i = 0; i < endindex; i++)
|
|
ipmipmn_if_ike_move(data, proc, ifp, coa, endpoints[i]);
|
|
|
|
return pending || endindex > 0;
|
|
|
|
#else
|
|
IPMIP_UNUSED_PARAMETER(ifp);
|
|
IPMIP_UNUSED_PARAMETER(data);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(coa);
|
|
return IP_FALSE;
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|