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

1029 lines
31 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip4_netlink_kern.c,v $ $Revision: 1.4.10.3 $
* $Source: /home/interpeak/CVSRoot/ipmip4/src/ipmip4_netlink_kern.c,v $
* $Author: jsheng $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipnet_config.h"
#if defined(IPNET)
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include <ipcom_err.h>
#include <ipcom_clib.h>
#include <ipcom_sysvar.h>
#include <ipcom_inet.h>
#include <ipcom_syslog.h>
#include "ipnet_h.h"
#include "ipnet.h"
#include <private/ipmip4_netlink_kern.h>
#include <ipmip.h>
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPMIP4_NETLINK_KERN_U32(rtap, val) ((rtap)[(val) - 1]? IP_GET_32ON8(IP_RTA_DATA((rtap)[(val) - 1])) : 0)
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipmip4_netlink_kern_handle
{
Ipmip_netlink_kern_handle_t handle;
Ipmip4_netlink_kern_statistics_t links[IPMIP_LINK_MAX];
} Ipmip4_netlink_kern_handle_t;
typedef struct Ipmip4_ipnet_route_func_info
{
struct Ipnet_route_func_info info;
/**/
Ipmip_netlink_route_flow_info_t flow;
Ip_bool have_gre_key;
Ip_u32 gre_key;
Ip_u32 link;
Ip_u32 flags;
Ipmip4_netlink_kern_handle_t *handle;
} Ipmip4_ipnet_route_func_info_t;
/*
****************************************************************************
* X STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC void *
ipmip4_ipnet_route_func_base(struct Ipnet_dst_cache_struct *dst,
struct Ipcom_pkt_struct *pkt)
{
Ipmip4_ipnet_route_func_info_t *rtinfo = (Ipmip4_ipnet_route_func_info_t*)dst->mip.flow_aux;
if (rtinfo->handle != IP_NULL)
{
rtinfo->handle->links[rtinfo->link].mip_s_octets += pkt->end - pkt->start;
rtinfo->handle->links[rtinfo->link].mip_s_pkts += 1;
rtinfo->handle->links[rtinfo->link].mip_s_stamp_sec = ipnet->sec_now;
rtinfo->handle->links[rtinfo->link].mip_s_stamp_msec = ipnet->msec_now - ipnet->msec_last;
}
return rtinfo;
}
IP_STATIC int
ipmip4_ipnet_route_func_gw_link_TX(struct Ipnet_dst_cache_struct *dst,
Ipcom_pkt *pkt)
{
Ipmip4_ipnet_route_func_info_t *rtinfo = ipmip4_ipnet_route_func_base(dst, pkt);
int ret;
/* Set GRE key */
if (rtinfo->have_gre_key)
ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_GRE_KEY_OUTPUT, sizeof(Ip_u32), &rtinfo->gre_key);
ret = (*dst->mip.flow_tx) (dst, pkt);
if (IP_UNLIKELY(ret < 0 && IP_BIT_ISSET(rtinfo->flags, IP_WRMOB4_NEW_TYPE_SILENT)))
ret = 0;
return ret;
}
IP_STATIC void
ipmip4_ipnet_dst_cache_func_gw_link_TX_init(Ip_bool init,
struct Ipnet_dst_cache_struct *dst)
{
if (init)
{
#if 0
dst->mip.flow_tx = dst->tx;
/**/
dst->tx = (Ipnet_dst_cache_tx_func)ipmip4_ipnet_route_func_gw_link_TX;
#else
dst->mip.flow_tx = dst->real_tx;
ipnet_dst_cache_set_tx_handler(dst, (Ipnet_dst_cache_tx_func)ipmip4_ipnet_route_func_gw_link_TX);
#endif
}
else
{
/* Free the AUX data */
ipcom_free(dst->mip.flow_aux);
}
}
IP_STATIC int
ipmip4_ipnet_route_func_gw_link_RX(struct Ipnet_dst_cache_struct *dst,
Ipcom_pkt *pkt)
{
Ipmip4_ipnet_route_func_info_t *rtinfo = ipmip4_ipnet_route_func_base(dst, pkt);
/* Set GRE key */
if (rtinfo->have_gre_key)
ipcom_pkt_set_info(pkt, IPNET_PKT_INFO_GRE_KEY_OUTPUT, sizeof(Ip_u32), &rtinfo->gre_key);
return (*dst->mip.flow_rx) (dst, pkt);
}
IP_STATIC void
ipmip4_ipnet_dst_cache_func_gw_link_RX_init(Ip_bool init,
struct Ipnet_dst_cache_struct *dst)
{
if (init)
{
#if 0
dst->mip.flow_rx = dst->rx;
dst->rx = (Ipnet_dst_cache_rx_func)ipmip4_ipnet_route_func_gw_link_RX;
#else
dst->mip.flow_rx = dst->real_rx;
ipnet_dst_cache_set_rx_handler(dst, (Ipnet_dst_cache_rx_func)ipmip4_ipnet_route_func_gw_link_RX);
#endif
}
else
{
/* Free the AUX data */
ipcom_free(dst->mip.flow_aux);
}
}
IP_STATIC int
ipmip4_netlink_kern_delmip_link_TX_RX(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta)
{
int ret;
struct Ip_rtattr **mattr = IP_NULL;
Ip_u32 domain;
Ip_u32 gwdomain;
Ipnet_rtnetlink_key_t ukey;
void *mask = IP_NULL;
struct Ip_sockaddr *gw = IP_NULL;
union Ip_sockaddr_union ugw;
(void)nlmsg;
if (!rta[IP_MIP_ENCAP - 1])
return -IP_ERRNO_EINVAL;
ret = ipnet_netlink_parse(IP_WRMOB4_ROUTE_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
return ret;
if (!mattr || !mattr[IP_WRMOB4_ROUTE_DST - 1])
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
/* Create the mask */
if (IP_RTA_PAYLOAD(mattr[IP_WRMOB4_ROUTE_DST - 1]) == sizeof(struct Ip_in_addr))
domain = IP_AF_INET;
else
{
#ifdef IPCOM_USE_INET6
domain = IP_AF_INET6;
#else
ret = -IP_ERRNO_EINVAL;
goto done;
#endif
}
/* Create the mask */
ret = ipnet_rtnetlink_route_key_setup(domain,
&ukey,
IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_IFINDEX),
&mask,
IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_DST_LEN),
mattr[IP_WRMOB4_ROUTE_DST - 1]);
if (ret < 0)
{
IPCOM_LOG0(ERR, "Unable to parse route, data");
goto done;
}
gwdomain = domain;
if (mattr[IP_WRMOB4_ROUTE_GW - 1])
{
if (IP_RTA_PAYLOAD(mattr[IP_WRMOB4_ROUTE_GW - 1]) == sizeof(struct Ip_in_addr))
gwdomain = IP_AF_INET;
else
{
if (IP_RTA_PAYLOAD(mattr[IP_WRMOB4_ROUTE_GW - 1]) == sizeof(struct Ip_sockaddr_dl))
{
gw = (struct Ip_sockaddr *)IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_GW - 1]);
gwdomain = IP_AF_LINK;
}
else
{
#ifdef IPCOM_USE_INET6
gwdomain = IP_AF_INET6;
#else
ret = -IP_ERRNO_EINVAL;
goto done;
#endif
}
}
}
if (gwdomain != IP_AF_LINK)
{
ret = ipnet_rtnetlink_route_gw_setup(gwdomain,
IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_IFINDEX),
&ugw,
&gw,
mattr[IP_WRMOB4_ROUTE_GW - 1]);
if (ret < 0)
{
IPCOM_LOG0(ERR, "Unable to parse route data");
goto done;
}
}
/* Do a referenced removal */
ret = ipnet_route_delete2(domain,
mem->vr,
IPCOM_ROUTE_TABLE_GET(IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_TABLE)),
&ukey,
mask,
gw,
IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_IFINDEX),
0,
0,
IP_TRUE);
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
IP_STATIC int
ipmip4_netlink_kern_delmip_handle(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta)
{
int ret;
struct Ip_rtattr **mattr = IP_NULL;
(void)nlmsg;
if (!rta[IP_MIP_ENCAP - 1])
return -IP_ERRNO_EINVAL;
ret = ipnet_netlink_parse(IP_WRMOB4_ROUTE_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
return ret;
if (!mattr || !mattr[IP_WRMOB4_ROUTE_HANDLE - 1])
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
/* Delete the handle */
ipmip_netlink_kern_handle_free(mem->vr, IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_HANDLE - 1]));
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
IP_STATIC int
ipmip4_netlink_kern_delmip_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
struct Ip_mipmsg *msg = IP_NLMSG_DATA(nlmsg);
(void)family;
(void)mem;
switch (msg->mip_type)
{
case IP_WRMOB4_DEL_LINK_TX:
case IP_WRMOB4_DEL_LINK_RX:
return ipmip4_netlink_kern_delmip_link_TX_RX(mem,nlmsg,rta);
case IP_WRMOB4_DEL_HANDLE:
return ipmip4_netlink_kern_delmip_handle(mem,nlmsg,rta);
default:
return -IP_ERRNO_EOPNOTSUPP;
}
}
IP_STATIC int
ipmip4_netlink_kern_setmip_address(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
Ip_bool doset)
{
int ret = 0;
struct Ip_rtattr **mattr = IP_NULL;
Ipnet_netif *netif;
(void)nlmsg;
if (!rta[IP_MIP_ENCAP - 1])
return -IP_ERRNO_EINVAL;
ret = ipnet_netlink_parse(IP_WRMOB4_HOA_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
return ret;
if (!mattr || !mattr[IP_WRMOB4_HOA_ADDRESS - 1] || !mattr[IP_WRMOB4_HOA_IFINDEX -1])
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
/* Locate the interface */
netif = ipnet_if_indextonetif(mem->vr, IP_GET_32ON8(IP_RTA_DATA(mattr[IP_WRMOB4_HOA_IFINDEX - 1])));
if (netif == IP_NULL)
{
ret = -IP_ERRNO_ENXIO;
goto done;
}
if (doset)
ipmip_netlink_kern_hoa_activate(netif, mattr[IP_WRMOB4_HOA_ADDRESS - 1]);
else
ipmip_netlink_kern_hoa_deactivate(netif, mattr[IP_WRMOB4_HOA_ADDRESS - 1]);
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
IP_STATIC int
ipmip4_netlink_kern_setmip_no_global_src(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
Ip_bool doset)
{
int ret = 0;
struct Ip_rtattr **mattr = IP_NULL;
Ipnet_netif *netif;
(void)nlmsg;
if (!rta[IP_MIP_ENCAP - 1])
return -IP_ERRNO_EINVAL;
ret = ipnet_netlink_parse(IP_WRMOB4_HOA_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
return ret;
if (!mattr || !mattr[IP_WRMOB4_HOA_IFINDEX -1])
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
/* Locate the interface */
netif = ipnet_if_indextonetif(mem->vr, IP_GET_32ON8(IP_RTA_DATA(mattr[IP_WRMOB4_HOA_IFINDEX - 1])));
if (netif == IP_NULL)
{
ret = -IP_ERRNO_ENXIO;
goto done;
}
if (doset)
ipmip_netlink_kern_if_exclude(netif);
else
ipmip_netlink_kern_if_include(netif);
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_link_setlink
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipmip4_netlink_kern_setmip_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
struct Ip_mipmsg *msg = IP_NLMSG_DATA(nlmsg);
(void)family;
/* */
switch (msg->mip_type)
{
case IP_WRMOB4_SET_ADDRESS_ACTIVE:
return ipmip4_netlink_kern_setmip_address(mem, nlmsg, rta, IP_BIT_ISFALSE(msg->mip_flags, IP_WRMOB4_SET_FLAG_CLEAR));
case IP_WRMOB4_SET_NO_GLOBAL_SRC:
return ipmip4_netlink_kern_setmip_no_global_src(mem, nlmsg, rta, IP_BIT_ISFALSE(msg->mip_flags, IP_WRMOB4_SET_FLAG_CLEAR));
}
return -IP_ERRNO_EOPNOTSUPP;
}
IP_STATIC int
ipmip4_netlink_kern_getmip_statistics(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta)
{
int ret;
struct Ip_mipmsg *msg;
struct Ip_nlmsghdr *nlh;
struct Ip_rtattr **mattr = IP_NULL;
Ipmip4_netlink_kern_handle_t *handle;
if (!rta[IP_MIP_ENCAP - 1])
return -IP_ERRNO_EINVAL;
ret = ipnet_netlink_parse(IP_WRMOB4_ROUTE_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
return ret;
if (!mattr || !mattr[IP_WRMOB4_ROUTE_HANDLE - 1])
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
/* Delete the handle */
handle = (Ipmip4_netlink_kern_handle_t *)ipmip_netlink_kern_handle_get(mem->vr, IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_HANDLE - 1]));
if (handle == IP_NULL)
{
ret = -IP_ERRNO_ENOENT;
goto done;
}
ret = -IP_ERRNO_ENOMEM;
/* Create the response */
nlh = ipnet_netlink_nlmsg_sz_begin(mem, nlmsg->nlmsg_seq, IP_RTM_GETMIP, 0);
if (!nlh)
goto done;
/**/
msg = ipnet_netlink_sz_put(mem, IP_NULL, sizeof(*msg));
if (!msg)
goto done;
/* Add route message header */
msg->mip_family = IP_AF_INET;
msg->mip_flags = 0;
msg->mip_type = IP_WRMOB4_GET_HANDLE_STAT;
/* */
{
struct Ip_rtattr *rep;
rep = ipnet_rtnetlink_rta_sz_nested_begin(mem, IP_MIP_ENCAP);
if (!rep)
goto done;
/* Put inbound statistics */
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_WRMOB4_STATS_LINK_RECV, sizeof(handle->links[IPMIP_LINK_RECV]), &handle->links[IPMIP_LINK_RECV]))
goto done;
/* Put inbound statistics */
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_WRMOB4_STATS_LINK_SEND, sizeof(handle->links[IPMIP_LINK_SEND]), &handle->links[IPMIP_LINK_SEND]))
goto done;
ipnet_rtnetlink_rta_sz_nested_end(mem, rep);
}
/* Done */
ret = ipnet_netlink_nlmsg_sz_end(mem, nlh);
if (ret >= 0)
{
handle->links[IPMIP_LINK_RECV].mip_s_octets = 0;
handle->links[IPMIP_LINK_RECV].mip_s_pkts = 0;
handle->links[IPMIP_LINK_SEND].mip_s_octets = 0;
handle->links[IPMIP_LINK_SEND].mip_s_pkts = 0;
}
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
IP_STATIC int
ipmip4_netlink_kern_getmip_validate_route(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta)
{
int ret;
Ipnet_route_entry *re;
struct Ip_mipmsg *msg;
struct Ip_nlmsghdr *nlh;
struct Ip_rtattr **mattr = IP_NULL;
if (!rta[IP_MIP_ENCAP - 1])
return -IP_ERRNO_EINVAL;
ret = ipnet_netlink_parse(IP_WRMOB4_ROUTE_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
return ret;
if (!mattr || !mattr[IP_WRMOB4_ROUTE_DST - 1])
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
/* Create the mask */
if (IP_RTA_PAYLOAD(mattr[IP_WRMOB4_ROUTE_DST - 1]) != sizeof(struct Ip_in_addr))
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
ret = ipnet_route_raw_lookup(IP_AF_INET,
mem->vr,
IPCOM_ROUTE_TABLE_GET(IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_TABLE)),
0,
IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_DST - 1]),
0,
IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_IFINDEX),
&re);
if (ret < 0)
goto done;
/* Create the response */
nlh = ipnet_netlink_nlmsg_sz_begin(mem, nlmsg->nlmsg_seq, IP_RTM_GETMIP, 0);
if (!nlh)
goto done;
/**/
msg = ipnet_netlink_sz_put(mem, IP_NULL, sizeof(*msg));
if (!msg)
goto done;
/* Add route message header */
msg->mip_family = IP_AF_INET;
msg->mip_flags = 0;
msg->mip_type = IP_WRMOB4_GET_VALIDATE_ROUTE;
/* Done */
ret = ipnet_netlink_nlmsg_sz_end(mem, nlh);
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
IP_STATIC int
ipmip4_netlink_kern_getmip_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
struct Ip_mipmsg *msg = IP_NLMSG_DATA(nlmsg);
(void) family;
switch (msg->mip_type)
{
case IP_WRMOB4_GET_HANDLE_STAT:
return ipmip4_netlink_kern_getmip_statistics(mem, nlmsg, rta);
case IP_WRMOB4_GET_VALIDATE_ROUTE:
return ipmip4_netlink_kern_getmip_validate_route(mem, nlmsg, rta);
}
return -IP_ERRNO_EOPNOTSUPP;
}
IP_STATIC int
ipmip4_netlink_kern_newmip_link_TX_RX(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
Ip_u8 flags,
Ipnet_dst_cache_mip_handle func)
{
int ret = 0;
struct Ipnet_route_add_param params;
Ipmip4_ipnet_route_func_info_t mipinfo;
struct Ipnet_rt_metrics metric;
Ipnet_rtnetlink_key_t ukey;
void *mask = IP_NULL;
struct Ip_rtattr **mattr = IP_NULL;
struct Ip_sockaddr *gw = IP_NULL;
union Ip_sockaddr_union ugw;
Ip_u32 domain;
(void)nlmsg;
if (!rta[IP_MIP_ENCAP - 1])
{
IPCOM_LOG0(ERR, "Required WRMOB4 route-gw parameter is missing");
return -IP_ERRNO_EINVAL;
}
ret = ipnet_netlink_parse(IP_WRMOB4_ROUTE_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
{
IPCOM_LOG0(ERR, "Unable to parse route-gw parameters");
return ret;
}
/* Required destination */
if (!mattr || !mattr[IP_WRMOB4_ROUTE_DST - 1])
{
IPCOM_LOG0(ERR, "Required WRMOB4 route-gw parameters were missing");
ret = -IP_ERRNO_EINVAL;
goto done;
}
ipcom_memset(&params, 0, sizeof(params));
ipcom_memset(&ukey, 0, sizeof(ukey));
ipcom_memset(&mipinfo, 0, sizeof(mipinfo));
ipcom_memset(&metric, 0, sizeof(metric));
/**/
metric.rmx_hopcount = 0;
if (IP_BIT_ISSET(flags, IP_WRMOB4_NEW_TYPE_TEMPORARY))
metric.rmx_expire = 5;
else
metric.rmx_expire = IPCOM_ADDR_INFINITE;
if (mattr[IP_WRMOB4_ROUTE_MTU - 1])
metric.rmx_mtu = IP_GET_32ON8(IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_MTU - 1]));
params.metrics = &metric;
params.key = &ukey;
params.vr = mem->vr;
params.table = IPCOM_ROUTE_TABLE_GET(IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_TABLE));
if (mattr[IP_WRMOB4_ROUTE_HANDLE - 1])
{
mipinfo.handle = (Ipmip4_netlink_kern_handle_t *)ipmip_netlink_kern_handle_get(mem->vr, IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_HANDLE - 1]));
if (mipinfo.handle == IP_NULL)
{
ret = -IP_ERRNO_ENOENT;
goto done;
}
}
params.netif = ipnet_if_indextonetif(mem->vr, IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_IFINDEX));
if (params.netif == IP_NULL)
{
IPCOM_LOG0(ERR, "Unable to locate route-gw interface");
ret = -IP_ERRNO_ENXIO;
goto done;
}
/* Gre KEY? */
if (mattr[IP_WRMOB4_ROUTE_GRE_KEY - 1])
{
mipinfo.have_gre_key = IP_TRUE;
mipinfo.gre_key = IP_GET_32ON8(IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_GRE_KEY - 1]));
}
if (mattr[IP_WRMOB4_ROUTE_LINK - 1])
mipinfo.link = IP_GET_32ON8(IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_LINK - 1]));
/* Create the mask */
if (IP_RTA_PAYLOAD(mattr[IP_WRMOB4_ROUTE_DST - 1]) == sizeof(struct Ip_in_addr))
params.domain = IP_AF_INET;
else
{
#ifdef IPCOM_USE_INET6
params.domain = IP_AF_INET6;
#else
ret = -IP_ERRNO_EINVAL;
goto done;
#endif
}
ret = ipnet_rtnetlink_route_key_setup(params.domain,
&ukey,
params.netif->ipcom.ifindex,
&mask,
IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_DST_LEN),
mattr[IP_WRMOB4_ROUTE_DST - 1]);
if (ret < 0)
{
IPCOM_LOG0(ERR, "Unable to parse route-gw data");
goto done;
}
domain = params.domain;
if (mattr[IP_WRMOB4_ROUTE_GW - 1])
{
if (IP_RTA_PAYLOAD(mattr[IP_WRMOB4_ROUTE_GW - 1]) == sizeof(struct Ip_in_addr))
domain = IP_AF_INET;
else
{
if (IP_RTA_PAYLOAD(mattr[IP_WRMOB4_ROUTE_GW - 1]) == sizeof(struct Ip_sockaddr_dl))
{
gw = (struct Ip_sockaddr *)IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_GW - 1]);
domain = IP_AF_LINK;
params.flags |= IPNET_RTF_LLINFO;
}
else
{
#ifdef IPCOM_USE_INET6
domain = IP_AF_INET6;
#else
ret = -IP_ERRNO_EINVAL;
goto done;
#endif
}
}
}
if (domain != IP_AF_LINK)
{
ret = ipnet_rtnetlink_route_gw_setup(domain, params.netif->ipcom.ifindex, &ugw, &gw, mattr[IP_WRMOB4_ROUTE_GW - 1]);
if (ret < 0)
{
IPCOM_LOG0(ERR, "Unable to parse route-gw data");
goto done;
}
}
if (mattr[IP_WRMOB4_ROUTE_NAT_PORT - 1])
{
Ip_u32 nat_port = IP_GET_32ON8(IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_NAT_PORT - 1]));
Ip_u32 nat_type = nat_port >> 16;
nat_port &= 0xFFFF;
if (nat_type == 0)
nat_type = IP_UDP_NAT_T_DSMIPV6;
/* */
if (gw != IP_NULL)
{
if (gw->sa_family == IP_AF_INET)
{
struct Ip_sockaddr_in *s_in = (struct Ip_sockaddr_in *)gw;
/* Set the DSMIPv6 NAT type */
s_in->sin_port = (Ip_u16)nat_port;
s_in->sin_zero[0] = (Ip_u8)nat_type;
}
}
}
params.netmask = mask;
/* May need it for the compare */
mipinfo.info.rt_info_size = sizeof(mipinfo);
mipinfo.flags = flags;
params.rtinfo = &mipinfo.info;
params.flags |= IPMIP4_NETLINK_KERN_U32(mattr, IP_WRMOB4_ROUTE_FLAGS);
params.flags |= IPNET_RTF_UP | IPNET_RTF_DONE | IPNET_RTF_PREF;
params.gateway = gw;
if (!params.netmask)
params.flags |= IPNET_RTF_HOST;
/* Set the flow match/init function */
ipmip_netlink_kern_rt_flow_set(&mipinfo.info,
mattr[IP_WRMOB4_ROUTE_SRCMAC - 1]? IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_SRCMAC - 1]) : IP_NULL,
func);
if (IP_BIT_ISSET(flags, IP_WRMOB4_NEW_TYPE_TEMPORARY))
{
ret = ipnet_route_delete2(params.domain,
params.vr,
params.table,
params.key,
params.netmask,
IP_NULL,
0,
0,
0,
IP_FALSE);
params.no_ref_count = IP_TRUE;
}
ret = ipnet_route_add(&params);
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
IP_STATIC int
ipmip4_netlink_kern_newmip_handle(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta)
{
int ret;
Ipmip4_netlink_kern_handle_t *nhandle;
Ipmip_netlink_kern_handle_t *handle;
struct Ip_rtattr **mattr = IP_NULL;
(void)nlmsg;
if (!rta[IP_MIP_ENCAP - 1])
return -IP_ERRNO_EINVAL;
ret = ipnet_netlink_parse(IP_WRMOB4_ROUTE_MAX,
IP_RTA_DATA(rta[IP_MIP_ENCAP - 1]),
IP_RTA_PAYLOAD(rta[IP_MIP_ENCAP - 1]),
&mattr);
if (ret < 0)
return ret;
if (!mattr || !mattr[IP_WRMOB4_ROUTE_HANDLE - 1])
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
handle = (Ipmip_netlink_kern_handle_t *)IP_RTA_DATA(mattr[IP_WRMOB4_ROUTE_HANDLE - 1]);
if (ipmip_netlink_kern_handle_get(mem->vr, handle))
{
ret = -IP_ERRNO_EEXIST;
goto done;
}
nhandle = ipcom_calloc(1, sizeof(*nhandle));
if (nhandle == IP_NULL)
{
ret = -IP_ERRNO_ENOMEM;
goto done;
}
ipcom_memcpy(&nhandle->handle, handle, sizeof(*handle));
/* Delete the handle */
ipmip_netlink_kern_handle_add(mem->vr, &nhandle->handle);
done:
if (mattr)
ipcom_free(mattr);
return ret;
}
IP_STATIC int
ipmip4_netlink_kern_newmip_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
struct Ip_mipmsg *msg = IP_NLMSG_DATA(nlmsg);
(void)family;
switch (msg->mip_type)
{
case IP_WRMOB4_NEW_LINK_TX:
return ipmip4_netlink_kern_newmip_link_TX_RX(mem, nlmsg, rta, msg->mip_flags, (Ipnet_dst_cache_mip_handle)ipmip4_ipnet_dst_cache_func_gw_link_TX_init);
case IP_WRMOB4_NEW_LINK_RX:
return ipmip4_netlink_kern_newmip_link_TX_RX(mem, nlmsg, rta, msg->mip_flags, (Ipnet_dst_cache_mip_handle)ipmip4_ipnet_dst_cache_func_gw_link_RX_init);
case IP_WRMOB4_NEW_HANDLE:
return ipmip4_netlink_kern_newmip_handle(mem, nlmsg, rta);
}
return -IP_ERRNO_EOPNOTSUPP;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL void
ipmip4_rtnetlink_init(void)
{
/* AF_UNSPEC */
ipnet_rtnetlink_register_family_event(IP_AF_INET, IP_RTM_DELMIP,
IP_MIP_MAX, sizeof(struct Ip_mipmsg),
ipmip4_netlink_kern_delmip_family,
IP_NULL);
ipnet_rtnetlink_register_family_event(IP_AF_INET, IP_RTM_NEWMIP,
IP_MIP_MAX, sizeof(struct Ip_mipmsg),
ipmip4_netlink_kern_newmip_family,
IP_NULL);
ipnet_rtnetlink_register_family_event(IP_AF_INET, IP_RTM_SETMIP,
IP_MIP_MAX, sizeof(struct Ip_mipmsg),
ipmip4_netlink_kern_setmip_family,
IP_NULL);
ipnet_rtnetlink_register_family_event(IP_AF_INET, IP_RTM_GETMIP,
IP_MIP_MAX, sizeof(struct Ip_mipmsg),
ipmip4_netlink_kern_getmip_family,
IP_NULL);
}
#else
int ipmip4_netlink_kern_empty_file = 0;
#endif
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/