632 lines
18 KiB
C
632 lines
18 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_rtnetlink.c,v $ $Revision: 1.11.10.1 $
|
|
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_rtnetlink.c,v $
|
|
* $Author: svc-cmnet $
|
|
* $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"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_route.h>
|
|
#include <ipcom_errno.h>
|
|
|
|
#include "ipnet_h.h"
|
|
#include "ipnet_ctrl.h"
|
|
#include "ipnet_route.h"
|
|
#include "ipnet_netlink_h.h"
|
|
#include "ipnet_rtnetlink_h.h"
|
|
#include "ipcom_sock.h"
|
|
#include "ipnet_eth.h"
|
|
|
|
#ifdef IPNET_USE_NETLINK
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_netlink_register_ops
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipnet_rtnetlink_register_family_event(int family,
|
|
int cmd,
|
|
Ip_size_t maxattr,
|
|
Ip_size_t min_size,
|
|
Ipnet_rtnetlink_do_t doit,
|
|
Ipnet_netlink_dump_t dumpit)
|
|
{
|
|
Ipnet_rtnetlink_table_t *table;
|
|
Ipnet_rtnetlink_config_t *rtcfg = ipnet->netlink_data[IP_NETLINK_ROUTE];
|
|
|
|
/**/
|
|
if (rtcfg->family_event[family] == IP_NULL)
|
|
{
|
|
rtcfg->family_event[family] = ipcom_calloc(IP_RTM_NR_MSGTYPES, sizeof(Ipnet_rtnetlink_table_t *));
|
|
ip_assert(rtcfg->family_event[family] != IP_NULL);
|
|
}
|
|
|
|
ip_assert(rtcfg->family_event[family][cmd - IP_RTM_BASE] == IP_NULL);
|
|
|
|
rtcfg->family_event[family][cmd - IP_RTM_BASE] = ipcom_calloc(1, sizeof(Ipnet_rtnetlink_table_t));
|
|
|
|
ip_assert(rtcfg->family_event[family][cmd - IP_RTM_BASE] != IP_NULL);
|
|
|
|
table = rtcfg->family_event[family][cmd - IP_RTM_BASE];
|
|
|
|
table->nl_cmd = cmd;
|
|
table->nl_func_table.nl_rta_max = maxattr;
|
|
table->nl_func_table.nl_size_min = IP_NLMSG_LENGTH(min_size);
|
|
table->nl_func_table.nl_do = doit;
|
|
table->nl_func_table.nl_dump = dumpit;
|
|
}
|
|
|
|
#ifdef IPNET_USE_NETLINKSOCK
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_register_ops
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipnet_rtnetlink_register_ops(struct Ip_rtnl_link_ops *ops)
|
|
{
|
|
ops->next = ipnet->rtnetlink_ops;
|
|
ipnet->rtnetlink_ops = ops;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_get_ops
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL struct Ip_rtnl_link_ops *
|
|
ipnet_rtnetlink_get_ops(const char *kind)
|
|
{
|
|
struct Ip_rtnl_link_ops *ops = ipnet->rtnetlink_ops;
|
|
|
|
while (ops != IP_NULL)
|
|
{
|
|
if (ipcom_strcmp(ops->kind, kind) == 0)
|
|
return ops;
|
|
ops = ops->next;
|
|
}
|
|
|
|
return IP_NULL;
|
|
}
|
|
#endif /* IPNET_USE_NETLINK_SOCK */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_rta_sz_put
|
|
*===========================================================================
|
|
* Description: Add a NETLINK route attribute to a NETLINK message.
|
|
* Parameters: nlh - Current NLMSG
|
|
* sz - Total size
|
|
* attrtype - Attribute type
|
|
* attrlen - Lenght of attribute
|
|
* data - Attribute data
|
|
*
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void *
|
|
ipnet_rtnetlink_rta_sz_put(Ipnet_netlink_mem_t *mem, Ip_u16 attrtype, Ip_size_t attrlen, IP_CONST void *data)
|
|
{
|
|
struct Ip_rtattr *rta = ipnet_netlink_sz_put(mem, IP_NULL, IP_RTA_LENGTH(attrlen));
|
|
|
|
if (!rta)
|
|
return IP_NULL;
|
|
|
|
rta->rta_type = (Ip_u16) attrtype;
|
|
rta->rta_len = (Ip_u16) IP_RTA_LENGTH (attrlen);
|
|
|
|
if (data)
|
|
ipcom_memcpy(IP_RTA_DATA(rta), data, attrlen);
|
|
|
|
return rta;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_rta_sz_put_u32
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void *
|
|
ipnet_rtnetlink_rta_sz_put_u32(Ipnet_netlink_mem_t *mem,
|
|
Ip_u16 atype,
|
|
Ip_u32 val)
|
|
{
|
|
/* Reinvoke */
|
|
return ipnet_rtnetlink_rta_sz_put(mem, atype, sizeof(val), &val);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_rta_sz_nested_begin
|
|
*===========================================================================
|
|
* Description: Begin a nested NETLINK route attribute to a NETLINK message.
|
|
* Parameters: nlh - Current NLMSG
|
|
* sz - Total size
|
|
* attrtype - Attribute type
|
|
*
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void *
|
|
ipnet_rtnetlink_rta_sz_nested_begin(Ipnet_netlink_mem_t *mem, Ip_u16 attrtype)
|
|
{
|
|
struct Ip_rtattr *rta = ipnet_netlink_sz_put(mem, IP_NULL, IP_RTA_LENGTH(0));
|
|
|
|
if (!rta)
|
|
return IP_NULL;
|
|
|
|
rta->rta_type = (Ip_u16) attrtype;
|
|
rta->rta_len = (Ip_u16) IP_RTA_LENGTH (0);
|
|
|
|
return rta;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_rta_sz_nested_end
|
|
*===========================================================================
|
|
* Description: Terminates a nested RTA.
|
|
* Parameters: nlh - Current NLMSG
|
|
* rta - Total size
|
|
* attrtype - Attribute type
|
|
*
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipnet_rtnetlink_rta_sz_nested_end(Ipnet_netlink_mem_t *mem, void *nested)
|
|
{
|
|
char *eptr = &mem->ptr[mem->used + mem->offset];
|
|
struct Ip_rtattr *rta = nested;
|
|
|
|
rta->rta_len = (Ip_u16) (eptr - (char *)rta);
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ipnet_rtnetlink_func_table_t *
|
|
ipnet_rtnetlink_family_get_do(struct Ipnet_rtnetlink_table ***table,
|
|
int family,
|
|
int cmd)
|
|
{
|
|
if (family < IP_AF_MAX && cmd >= IP_RTM_BASE && cmd-IP_RTM_BASE <= IP_RTM_NR_MSGTYPES)
|
|
{
|
|
Ipnet_rtnetlink_table_t **tbl = table[family];
|
|
if (tbl)
|
|
{
|
|
if (tbl[cmd - IP_RTM_BASE] && tbl[cmd - IP_RTM_BASE]->nl_func_table.nl_do)
|
|
return &tbl[cmd - IP_RTM_BASE]->nl_func_table;
|
|
}
|
|
|
|
if (family != IP_AF_UNSPEC)
|
|
return ipnet_rtnetlink_family_get_do(table, IP_AF_UNSPEC, cmd);
|
|
}
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
IP_GLOBAL Ipnet_rtnetlink_func_table_t *
|
|
ipnet_rtnetlink_family_get_dump(struct Ipnet_rtnetlink_table ***table,
|
|
int family,
|
|
int cmd)
|
|
{
|
|
if (family < IP_AF_MAX && cmd >= IP_RTM_BASE && cmd-IP_RTM_BASE <= IP_RTM_NR_MSGTYPES)
|
|
{
|
|
Ipnet_rtnetlink_table_t **tbl = table[family];
|
|
if (tbl)
|
|
{
|
|
if (tbl[cmd - IP_RTM_BASE] && tbl[cmd - IP_RTM_BASE]->nl_func_table.nl_dump)
|
|
return &tbl[cmd - IP_RTM_BASE]->nl_func_table;
|
|
}
|
|
|
|
if (family != IP_AF_UNSPEC)
|
|
return ipnet_rtnetlink_family_get_dump(table, IP_AF_UNSPEC, cmd);
|
|
}
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
#ifdef IPNET_USE_NETLINKSOCK
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_netlink_dump
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_rtnetlink_do(Ipnet_rtnetlink_do_t do_it,
|
|
int family,
|
|
Ipnet_socket *sock,
|
|
struct Ip_nlmsghdr *nlmsg,
|
|
Ip_bool non_blocking,
|
|
struct Ip_rtattr **rta)
|
|
{
|
|
Ipcom_pkt *pkt = IP_NULL;
|
|
Ipnet_netlink_mem_t mem;
|
|
int ret;
|
|
|
|
/* Is it a 'get'? */
|
|
if (((nlmsg->nlmsg_type - IP_RTM_BASE) & 0x3) == 2)
|
|
{
|
|
/**/
|
|
if (!ipnet_netlink_pkt_alloc(&pkt, sock, non_blocking, &mem, 512))
|
|
return -IP_ERRNO_ENOMEM;
|
|
}
|
|
else
|
|
{
|
|
/**/
|
|
ipnet_netlink_pkt_mem(IP_NULL, sock, &mem);
|
|
}
|
|
|
|
/* */
|
|
ret = (*do_it) (&mem, nlmsg, rta, family);
|
|
|
|
/* */
|
|
if (pkt != IP_NULL && ret > 0)
|
|
{
|
|
pkt->end += ret;
|
|
|
|
if (!ipnet_netlink_pkt_queue(&pkt, sock))
|
|
ret = -IP_ERRNO_ENOBUFS;
|
|
}
|
|
|
|
if (pkt)
|
|
ipcom_pkt_free(pkt);
|
|
return ret < 0? ret : 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_sock_send
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_rtnetlink_sock_send(Ipnet_socket *sock,
|
|
Ip_bool non_blocking,
|
|
struct Ip_nlmsghdr *nlmsg)
|
|
{
|
|
struct Ip_rtattr **rta = IP_NULL;
|
|
int ret = 0;
|
|
Ipnet_rtnetlink_func_table_t *tbl;
|
|
int family;
|
|
Ipnet_rtnetlink_config_t *rtcfg = ipnet->netlink_data[IP_NETLINK_ROUTE];
|
|
|
|
|
|
/* Need to retrieve the family byte */
|
|
if (nlmsg->nlmsg_len < IP_NLMSG_LENGTH(sizeof(struct Ip_rtgenmsg)))
|
|
return 0;
|
|
|
|
/* These messages are to be ignored */
|
|
if (nlmsg->nlmsg_type < IP_RTM_BASE)
|
|
return 0;
|
|
|
|
/**/
|
|
family = ((struct Ip_rtgenmsg*)IP_NLMSG_DATA(nlmsg))->rtgen_family;
|
|
|
|
/* Dump */
|
|
if (IP_BIT_ISSET(nlmsg->nlmsg_flags, IP_NLM_F_DUMP) && ((nlmsg->nlmsg_type - IP_RTM_BASE) & 0x3) == 2)
|
|
{
|
|
ret = -IP_ERRNO_EAFNOSUPPORT;
|
|
tbl = ipnet_rtnetlink_family_get_dump(rtcfg->family_event, family, nlmsg->nlmsg_type);
|
|
if (tbl == IP_NULL)
|
|
goto error_out;
|
|
|
|
ret = ipnet_netlink_dump(tbl->nl_dump, family, sock, nlmsg, non_blocking);
|
|
goto error_out;
|
|
}
|
|
|
|
tbl = ipnet_rtnetlink_family_get_do(rtcfg->family_event, family, nlmsg->nlmsg_type);
|
|
if (tbl == IP_NULL)
|
|
{
|
|
ret = -IP_ERRNO_EAFNOSUPPORT;
|
|
goto error_out;
|
|
}
|
|
else
|
|
{
|
|
struct Ip_rtattr *attr = IP_NULL;
|
|
Ip_size_t attrlen = 0;
|
|
|
|
/* Check minimum length. */
|
|
if (nlmsg->nlmsg_len < tbl->nl_size_min)
|
|
{
|
|
ret = -IP_ERRNO_EINVAL;
|
|
goto error_out;
|
|
}
|
|
|
|
/* */
|
|
if (nlmsg->nlmsg_len > tbl->nl_size_min)
|
|
{
|
|
attrlen = nlmsg->nlmsg_len - IP_NLMSG_ALIGN(tbl->nl_size_min);
|
|
attr = (struct Ip_rtattr*)((char *)nlmsg + IP_NLMSG_ALIGN(tbl->nl_size_min));
|
|
}
|
|
|
|
ret = ipnet_netlink_parse(tbl->nl_rta_max, attr, attrlen, &rta);
|
|
if (ret < 0)
|
|
goto error_out;
|
|
}
|
|
|
|
/* DO */
|
|
ret = ipnet_rtnetlink_do(tbl->nl_do, family, sock, nlmsg, non_blocking, (void *)rta);
|
|
|
|
error_out:
|
|
if (rta)
|
|
ipcom_free(rta);
|
|
return IP_MIN(ret, 0);
|
|
}
|
|
|
|
|
|
#endif /* IPNET_USE_NETLINK_SOCK */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_netlink_broadcast
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipnet_rtnetlink_broadcast(Ipcom_pkt *pkt, int msg_group)
|
|
{
|
|
ipnet_netlink_broadcast(pkt, IP_NETLINK_ROUTE, msg_group);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_vr
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_u16
|
|
ipnet_rtnetlink_vr(struct Ip_rtattr *rta, Ip_u16 vr)
|
|
{
|
|
if (rta)
|
|
return (Ip_u16)IP_GET_32ON8(IP_RTA_DATA(rta));
|
|
return vr;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_dump_family
|
|
*===========================================================================
|
|
* Description: Generic netlink address dumper.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_rtnetlink_addr_dump_family(Ipnet_netlink_mem_t *mem,
|
|
struct Ip_nlmsghdr *nlh,
|
|
int family,
|
|
Ip_ptrdiff_t *args)
|
|
{
|
|
|
|
int req_type;
|
|
|
|
/**/
|
|
switch (nlh->nlmsg_type)
|
|
{
|
|
case IP_RTM_GETMULTICAST:
|
|
req_type = IPNET_ADDR_TYPE_MULTICAST;
|
|
break;
|
|
case IP_RTM_GETANYCAST:
|
|
req_type = IPNET_ADDR_TYPE_ANYCAST;
|
|
break;
|
|
default:
|
|
req_type = IPNET_ADDR_TYPE_UNICAST;
|
|
break;
|
|
}
|
|
|
|
switch (family)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
return ipnet_rtnetlink_ip4_addr_dump(mem, nlh, req_type, args);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
return ipnet_rtnetlink_ip6_addr_dump(mem, nlh, req_type, args);
|
|
#endif
|
|
default:
|
|
return -IP_ERRNO_EAFNOSUPPORT;
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_addr_newaddr_family
|
|
*===========================================================================
|
|
* Description: Generic netlink address add handler
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_rtnetlink_addr_newaddr_family(Ipnet_netlink_mem_t *mem,
|
|
struct Ip_nlmsghdr *nlh,
|
|
struct Ip_rtattr **rta,
|
|
int family)
|
|
{
|
|
switch (family)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
return ipnet_rtnetlink_ip4_newaddr(mem, nlh, rta);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
return ipnet_rtnetlink_ip6_newaddr(mem, nlh, rta);
|
|
#endif
|
|
default:
|
|
return -IP_ERRNO_EAFNOSUPPORT;;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_rtnetlink_addr_deladdr_family
|
|
*===========================================================================
|
|
* Description: Generic netlink address delete handler
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_rtnetlink_addr_deladdr_family(Ipnet_netlink_mem_t *mem,
|
|
struct Ip_nlmsghdr *nlh,
|
|
struct Ip_rtattr **rta,
|
|
int family)
|
|
{
|
|
switch (family)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
return ipnet_rtnetlink_ip4_deladdr(mem, nlh, rta);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
return ipnet_rtnetlink_ip6_deladdr(mem, nlh, rta);
|
|
#endif
|
|
default:
|
|
return -IP_ERRNO_EAFNOSUPPORT;
|
|
}
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipnet_rtnetlink_init(void)
|
|
{
|
|
ipnet->netlink_data[IP_NETLINK_ROUTE] = ipcom_calloc(1, sizeof(Ipnet_rtnetlink_config_t));
|
|
ipnet_rtnetlink_link_init();
|
|
}
|
|
|
|
#endif /* IPNET_USE_NETLINK */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|