491 lines
17 KiB
C
491 lines
17 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip4_if.c,v $ $Revision: 1.24.16.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmip4/src/ipmip4_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 "ipmip4_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_drv_eth_filter.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_ipd.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock2.h>
|
|
#include <ipcom_sysctl.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_netif.h>
|
|
#include <ipcom_sysvar.h>
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_netlink.h>
|
|
#include <private/ipmip_log.h>
|
|
|
|
#include "ipmip4_h.h"
|
|
#include <private/ipmip4_util.h>
|
|
#include <private/ipmip4_if.h>
|
|
#include <private/ipmip4_pkt.h>
|
|
#include <private/ipmip4_pktbuf.h>
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip4_if_destroy_tunnel
|
|
*===========================================================================
|
|
* Description: Destroy a particular tunnel.
|
|
* Parameters: iff - The tunnel to destroy.
|
|
* Returns:
|
|
*/
|
|
IP_STATIC void
|
|
ipmip4_if_destroy_tunnel(Ipmip4_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip4_if_t *iff)
|
|
{
|
|
struct Ip_ifreq ifreq;
|
|
int i;
|
|
|
|
/* No tunnel, don't bother */
|
|
if (iff->ipmip.ifindex == 0)
|
|
return;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
/* Do down & destroy */
|
|
ipmip_if_clear_flags(&ctx->ipmip, proc, &iff->ipmip, IP_IFF_UP);
|
|
if (ipmip_if_ioctl(&ctx->ipmip, proc, &iff->ipmip, IP_SIOCIFDESTROY, &ifreq) < 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCIFDESTROY) failed: %s [%d]",
|
|
iff->ipmip.ifname,
|
|
ipcom_strerror(ipcom_errno),
|
|
ipcom_errno);
|
|
ipcom_sleep(1);
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG1(DEBUG, "tunnel interface '%s' destroyed",
|
|
iff->ipmip.ifname);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Reset index */
|
|
iff->ipmip.ifindex = 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip4_if_free
|
|
*===========================================================================
|
|
* Description: Destroy and free the interface specific data.
|
|
* Parameters: ctx - Context
|
|
* proc - Process
|
|
* iff - the interface to destroy
|
|
* Returns:
|
|
*/
|
|
IP_STATIC void
|
|
ipmip4_if_free(Ipmip4_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip4_if_t *iff)
|
|
{
|
|
/* Invoke cleanup functionality */
|
|
if (iff->cleanup)
|
|
(*iff->cleanup) (&ctx->ipmip, proc, &iff->ipmip);
|
|
|
|
/* Destroy this particular tunnel */
|
|
if (iff->ipmip.type == IPMIP_IF_TYPE_TUNNEL)
|
|
ipmip4_if_destroy_tunnel(ctx, proc, iff);
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip4_if_alloc
|
|
*===========================================================================
|
|
* Description: Allocate and initialize the interface structure
|
|
* Parameters: ctx - Context
|
|
* proc - Process
|
|
* ifsize - the size of the interface structure
|
|
* ifname - The interface name
|
|
* ifindex - The interface index.
|
|
* type - Type of interface
|
|
* identity- The interface identity.
|
|
* cleanup - Function to be invoked prior to free.
|
|
* Returns: The interface structure on success.
|
|
*/
|
|
IP_GLOBAL Ipmip4_if_t *
|
|
ipmip4_if_alloc(Ipmip4_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ip_size_t ifsize,
|
|
const char *ifname,
|
|
Ip_u32 ifindex,
|
|
Ip_u8 type,
|
|
Ip_u8 identity,
|
|
Ipmip_if_cleanup_t cleanup)
|
|
{
|
|
Ipmip4_if_t *iff = (Ipmip4_if_t *)ipmip_if_alloc(&ctx->ipmip,
|
|
proc,
|
|
ifsize,
|
|
ifname,
|
|
ifindex,
|
|
type,
|
|
identity,
|
|
(Ipmip_if_cleanup_t)ipmip4_if_free);
|
|
|
|
if (iff == IP_NULL)
|
|
return IP_NULL;
|
|
|
|
ipcom_list_init(&iff->pktbufs);
|
|
iff->cleanup = cleanup;
|
|
return iff;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmipfa_if_alloc_tunnel
|
|
*===========================================================================
|
|
* Description: Create a specific tunnel for the provided interface
|
|
* Parameters: ctx - Context
|
|
* proc - Process
|
|
* ifsize - Total size of the interface structure
|
|
* ifname - Wanted ifname
|
|
* local - The local endpoint
|
|
* local_port - Base port for NAT_T setup
|
|
* remote - Remote endpoint
|
|
* identity - The identity of the tunnel
|
|
* tunnel_type - Tunnel type
|
|
* reorder - Enable reordering if supported by interface
|
|
* cleanup - Function to be invoked prior to free.
|
|
* Returns: The interface structure on success.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmip4_if_t *
|
|
ipmip4_if_alloc_tunnel(Ipmip4_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ip_size_t ifsize,
|
|
char *ifname,
|
|
Ip_u32 local,
|
|
Ip_u16 local_port,
|
|
Ip_u32 remote,
|
|
Ip_u8 identity,
|
|
Ip_u8 tunnel_type,
|
|
Ip_bool reorder,
|
|
Ipmip_if_cleanup_t cleanup)
|
|
{
|
|
struct Ip_ifreq ifreq;
|
|
struct Ip_ifaliasreq alias;
|
|
struct Ip_ip_tunnel_param tun;
|
|
struct Ip_sockaddr_in *inaddr;
|
|
Ip_u16 flags;
|
|
Ipmip4_if_t *iff;
|
|
|
|
/* Allocate the structure */
|
|
iff = ipmip4_if_alloc(ctx, proc, ifsize, ifname, 0, IPMIP_IF_TYPE_TUNNEL, identity, cleanup);
|
|
if (iff == IP_NULL)
|
|
return IP_NULL;
|
|
|
|
/* Try create the interface */
|
|
if (ipmip_if_ioctl(&ctx->ipmip, proc, &iff->ipmip, IP_SIOCIFCREATE, &ifreq) < 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCIFCREATE) failed : %s [%d]",
|
|
iff->ipmip.ifname,
|
|
ipcom_strerror(ipcom_errno),
|
|
ipcom_errno);
|
|
goto destroy;
|
|
}
|
|
|
|
/* May have been modified */
|
|
ipcom_strncpy(iff->ipmip.ifname, ifreq.ifr_name, IP_IFNAMSIZ);
|
|
|
|
/* Store the index */
|
|
iff->ipmip.ifindex = ipcom_if_nametoindex(iff->ipmip.ifname);
|
|
iff->ipmip.tunnel_type = tunnel_type;
|
|
|
|
/* Change tunnel */
|
|
ipcom_memset(&tun, 0, sizeof(tun));
|
|
if((IP_IFNAMSIZ - 1) < strlen(iff->ipmip.ifname))
|
|
{
|
|
goto destroy;
|
|
}
|
|
ipcom_strcpy(tun.ifr_name, iff->ipmip.ifname);
|
|
|
|
tun.local_addr.sin.sin_family = IP_AF_INET;
|
|
tun.local_addr.sin.sin_addr.s_addr = local;
|
|
IPCOM_SA_LEN_SET(&tun.local_addr.sin, sizeof(struct Ip_sockaddr_in));
|
|
|
|
/* Prepare the tunnel for NAT-T */
|
|
tun.local_addr.sin.sin_port = local_port;
|
|
|
|
tun.remote_addr.sin.sin_family = IP_AF_INET;
|
|
tun.remote_addr.sin.sin_addr.s_addr = remote;
|
|
IPCOM_SA_LEN_SET(&tun.remote_addr.sin, sizeof(struct Ip_sockaddr_in));
|
|
tun.ttl = 64;
|
|
|
|
/* Set tunnel interface address */
|
|
if (local)
|
|
{
|
|
ipcom_memset(&alias, 0, sizeof(alias));
|
|
ipcom_strcpy(alias.ifra_name, ifreq.ifr_name);
|
|
|
|
inaddr = (struct Ip_sockaddr_in *)&alias.ifra_addr;
|
|
inaddr->sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(inaddr, sizeof(struct Ip_sockaddr_in));
|
|
inaddr->sin_addr.s_addr = local;
|
|
|
|
inaddr = (struct Ip_sockaddr_in *)&alias.ifra_mask;
|
|
inaddr->sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(inaddr, sizeof(struct Ip_sockaddr_in));
|
|
inaddr->sin_addr.s_addr = 0xffffffff;
|
|
|
|
/* Assign the CoA address */
|
|
if (ipmip_netlink_inX_addr(&ctx->ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, iff->ipmip.ifindex, &local, 32, 0, 0) < 0)
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&ctx->ipmip,
|
|
proc,
|
|
"Unable to assign address to tunnel interface %s",
|
|
iff->ipmip.ifname));
|
|
goto destroy;
|
|
}
|
|
}
|
|
|
|
/**/
|
|
flags = IP_IFF_UP;
|
|
if (tunnel_type == IPMIP_TUNNELTYPE_MINENC)
|
|
IP_BIT_SET(flags, IP_IFF_LINK0);
|
|
if (tunnel_type == IPMIP_TUNNELTYPE_GRE && reorder)
|
|
IP_BIT_SET(flags, IP_IFF_LINK1);
|
|
if (ipmip_if_set_flags(&ctx->ipmip, proc, &iff->ipmip, flags) < 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCSIFFLAGS) failed: %s [%d]",
|
|
iff->ipmip.ifname,
|
|
ipcom_strerror(ipcom_errno),
|
|
ipcom_errno);
|
|
goto destroy;
|
|
}
|
|
|
|
/* Set endpoints; will update minenc if set as well. */
|
|
if (ipmip_util_ioctl(&ctx->ipmip, proc, IP_SIOCCHGTUNNEL, &tun) < 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCCHGTUNNEL) failed: %s [%d]",
|
|
iff->ipmip.ifname,
|
|
ipcom_strerror(ipcom_errno),
|
|
ipcom_errno);
|
|
goto destroy;
|
|
}
|
|
|
|
return iff;
|
|
|
|
destroy:
|
|
ipmip_if_free(&ctx->ipmip, proc, &iff->ipmip);
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip4_if_get_primary_address
|
|
*===========================================================================
|
|
* Description: Get the current primary address of the interface.
|
|
* Parameters: iff - Interface
|
|
* Returns: address on success; IP_INADDR_NONE on failure.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_u32
|
|
ipmip4_if_get_primary_address(Ipmip4_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip4_if_t *iff)
|
|
{
|
|
Ipmip_buffer_t reply;
|
|
int ret;
|
|
Ip_u32 addr = IP_INADDR_NONE;
|
|
|
|
ipmip_buffer_init(&reply);
|
|
|
|
if ((ret = ipmip_netlink_inX_addr_dump(&ctx->ipmip, proc, IP_AF_INET, &reply)) < 0)
|
|
{
|
|
IPMIP4_EVENT_IF(ERR, proc,
|
|
ipmip_log_event_add(&ctx->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];
|
|
|
|
/* Resolve this entry; I want the prefix length and the address */
|
|
if (ifa->ifa_index == (Ip_s32)iff->ipmip.ifindex)
|
|
{
|
|
/* Parse */
|
|
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])
|
|
{
|
|
if (ifa->ifa_family == IP_AF_INET)
|
|
{
|
|
addr = IP_GET_32ON8(IP_RTA_DATA(ifap[IP_IFA_LOCAL]));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**/
|
|
nlh = IP_NLMSG_NEXT(nlh, nlh_size);
|
|
}
|
|
|
|
}
|
|
|
|
/**/
|
|
ipmip_buffer_release(&reply);
|
|
return addr;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip4_if_findbyaddr
|
|
*===========================================================================
|
|
* Description: Locate an interface in our configuration based on address.
|
|
* Parameters: iflist - The list of interfaces.
|
|
* addr - The interface address
|
|
* Returns: The interface pointer if it exists, IP_NULL otherwise.
|
|
*/
|
|
IP_GLOBAL Ipmip4_if_t *
|
|
ipmip4_if_findbyaddr(Ipcom_list *iflist,
|
|
Ip_u32 addr)
|
|
{
|
|
Ipmip4_if_t *iff;
|
|
|
|
for (iff = IPCOM_LIST_FIRST(iflist); iff; iff = IPCOM_LIST_NEXT(&iff->ipmip.next))
|
|
{
|
|
if (iff->ifaddr == addr)
|
|
return iff;
|
|
}
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip4_if_findbypktinfo
|
|
*===========================================================================
|
|
* Description: Locate an interface in our configuration based on address.
|
|
* Parameters: iflist - The list of interfaces
|
|
* pktinfo - The interface info
|
|
* Returns: The interface pointer if it exists, IP_NULL otherwise.
|
|
*/
|
|
IP_GLOBAL Ipmip4_if_t *
|
|
ipmip4_if_findbypktinfo(Ipcom_list *iflist,
|
|
Ipmip_pktbuf_pktinfo_t *pktinfo)
|
|
{
|
|
Ipmip4_if_t *iff;
|
|
|
|
if ((iff = ipmip4_if_findbyaddr(iflist, pktinfo->dst.sin.sin_addr.s_addr)) == IP_NULL)
|
|
iff = (Ipmip4_if_t *)ipmip_if_findbyindex(iflist, pktinfo->ifindex);
|
|
|
|
return iff;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|