499 lines
16 KiB
C
499 lines
16 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipcom_netlink.c,v $ $Revision: 1.2.46.2 $
|
|
* $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_netlink.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 "ipcom_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include "ipcom_type.h"
|
|
#include "ipcom_cstyle.h"
|
|
#include "ipcom_clib.h"
|
|
#include "ipcom_clib2.h"
|
|
#include "ipcom_sock.h"
|
|
#include "ipcom_netlink.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*** LINUX COMPAT MODE FLAGS ***/
|
|
#define IFF_LINUX_UP 0x1 /* IP_IFF_UP */
|
|
#define IFF_LINUX_BROADCAST 0x2 /* IP_IFF_BROADCAST */
|
|
#define IFF_LINUX_DEBUG 0x4 /* IP_IFF_DEBUG */
|
|
#define IFF_LINUX_LOOPBACK 0x8 /* IP_IFF_LOOPBACK */
|
|
#define IFF_LINUX_POINTOPOINT 0x10 /* IP_IFF_POINTTOPOINT */
|
|
#define IFF_LINUX_NOTRAILERS 0x20 /* NO MATCH */
|
|
#define IFF_LINUX_RUNNING 0x40 /* IP_IFF_RUNNING */
|
|
#define IFF_LINUX_NOARP 0x80 /* IP_IFF_NOARP */
|
|
#define IFF_LINUX_PROMISC 0x100 /* IP_IFF_PROMISC*/
|
|
#define IFF_LINUX_ALLMULTI 0x200 /* IP_IFF_ALLMULT */
|
|
#define IFF_LINUX_MASTER 0x400 /* IP_IFF_MASTER */
|
|
#define IFF_LINUX_SLAVE 0x800 /* IP_IFF_SLAVE */
|
|
#define IFF_LINUX_MULTICAST 0x1000 /* IP_IFF_MULTICAST */
|
|
#define IFF_LINUX_PORTSEL 0x2000
|
|
#define IFF_LINUX_DYNAMIC 0x8000
|
|
#define IFF_LINUX_LOWER_UP 0x10000
|
|
#define IFF_LINUX_DORMANT 0x20000
|
|
#define IFF_LINUX_ECHO 0x40000
|
|
#define IFF_LINUX_AUTOMEDIA 0x4000
|
|
|
|
#define IP_AF_INET6_LINUX 10
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* INTERFACE TRANSLATION FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC Ip_u32
|
|
ipcom_netlink_rtnl_translate_ifflags(int from, int to, Ip_u32 flags)
|
|
{
|
|
Ip_u32 nflags = flags;
|
|
int b;
|
|
|
|
if (from == IP_NETLINK_TRANSLATE_IPNET)
|
|
{
|
|
/* Switch from IPNET */
|
|
switch (to)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
nflags = 0;
|
|
for (b = 0; b < 32; b++)
|
|
{
|
|
if (IP_BIT_ISSET(flags, IP_BIT_VAL(b)))
|
|
{
|
|
switch (IP_BIT_VAL(b))
|
|
{
|
|
case IP_IFF_UP:
|
|
nflags |= IFF_LINUX_UP;
|
|
break;
|
|
case IP_IFF_BROADCAST:
|
|
nflags |= IFF_LINUX_BROADCAST;
|
|
break;
|
|
case IP_IFF_DEBUG:
|
|
nflags |= IFF_LINUX_DEBUG;
|
|
break;
|
|
case IP_IFF_LOOPBACK:
|
|
nflags |= IFF_LINUX_LOOPBACK;
|
|
break;
|
|
case IP_IFF_POINTOPOINT:
|
|
nflags |= IFF_LINUX_POINTOPOINT;
|
|
break;
|
|
case IP_IFF_RUNNING:
|
|
/* We do not have the linux lower up; map it to running */
|
|
nflags |= IFF_LINUX_RUNNING|IFF_LINUX_LOWER_UP;
|
|
break;
|
|
case IP_IFF_NOARP:
|
|
nflags |= IFF_LINUX_NOARP;
|
|
break;
|
|
case IP_IFF_PROMISC:
|
|
nflags |= IFF_LINUX_PROMISC;
|
|
break;
|
|
case IP_IFF_ALLMULTI:
|
|
nflags |= IFF_LINUX_ALLMULTI;
|
|
break;
|
|
case IP_IFF_MULTICAST:
|
|
nflags |= IFF_LINUX_MULTICAST;
|
|
break;
|
|
case IP_IFF_SLAVE:
|
|
nflags |= IFF_LINUX_SLAVE;
|
|
break;
|
|
case IP_IFF_MASTER:
|
|
nflags |= IFF_LINUX_MASTER;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Switch to IPNET */
|
|
switch (from)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
nflags = 0;
|
|
for (b = 0; b < 32; b++)
|
|
{
|
|
if (IP_BIT_ISSET(flags, IP_BIT_VAL(b)))
|
|
{
|
|
switch (IP_BIT_VAL(b))
|
|
{
|
|
case IFF_LINUX_UP:
|
|
nflags |= IP_IFF_UP;
|
|
break;
|
|
case IFF_LINUX_BROADCAST:
|
|
nflags |= IP_IFF_BROADCAST;
|
|
break;
|
|
case IFF_LINUX_DEBUG:
|
|
nflags |= IP_IFF_DEBUG;
|
|
break;
|
|
case IFF_LINUX_LOOPBACK:
|
|
nflags |= IP_IFF_LOOPBACK;
|
|
break;
|
|
case IFF_LINUX_POINTOPOINT:
|
|
nflags |= IP_IFF_POINTOPOINT;
|
|
break;
|
|
case IFF_LINUX_RUNNING:
|
|
nflags |= IP_IFF_RUNNING;
|
|
break;
|
|
case IFF_LINUX_NOARP:
|
|
nflags |= IP_IFF_NOARP;
|
|
break;
|
|
case IFF_LINUX_PROMISC:
|
|
nflags |= IP_IFF_PROMISC;
|
|
break;
|
|
case IFF_LINUX_ALLMULTI:
|
|
nflags |= IP_IFF_ALLMULTI;
|
|
break;
|
|
case IFF_LINUX_MULTICAST:
|
|
nflags |= IP_IFF_MULTICAST;
|
|
break;
|
|
case IFF_LINUX_SLAVE:
|
|
nflags |= IP_IFF_SLAVE;
|
|
break;
|
|
case IFF_LINUX_MASTER:
|
|
nflags |= IP_IFF_MASTER;
|
|
break;
|
|
case IFF_LINUX_LOWER_UP:
|
|
nflags |= IP_IFF_RUNNING;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nflags;
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipcom_netlink_rtnl_translate_family(int from, int to, struct Ip_nlmsghdr *nlh)
|
|
{
|
|
struct Ip_rtgenmsg *rtmsg = (struct Ip_rtgenmsg *)IP_NLMSG_DATA(nlh);
|
|
|
|
if (from == IP_NETLINK_TRANSLATE_IPNET)
|
|
{
|
|
/* Switch from IPNET */
|
|
switch (to)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
if (rtmsg->rtgen_family == IP_AF_INET6)
|
|
rtmsg->rtgen_family = IP_AF_INET6_LINUX;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Switch to IPNET */
|
|
switch (from)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
if (rtmsg->rtgen_family == IP_AF_INET6_LINUX)
|
|
rtmsg->rtgen_family = IP_AF_INET6;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipcom_netlink_rtnl_translate_route(int from, int to, struct Ip_nlmsghdr *nlh)
|
|
{
|
|
struct Ip_rtmsg *rtm = (struct Ip_rtmsg *)IP_NLMSG_DATA(nlh);
|
|
|
|
if (IP_NLMSG_PAYLOAD(nlh, 0) < sizeof(*rtm))
|
|
return;
|
|
|
|
if (from == IP_NETLINK_TRANSLATE_IPNET)
|
|
{
|
|
/* Switch from IPNET */
|
|
switch (to)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
if (rtm->rtm_type == IP_RTN_CLONE || rtm->rtm_type == IP_RTN_PROXY)
|
|
{
|
|
if (rtm->rtm_type == IP_RTN_CLONE)
|
|
IP_BIT_SET(rtm->rtm_flags, IP_RTM_F_CLONED);
|
|
rtm->rtm_type = IP_RTN_UNICAST;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Switch to IPNET */
|
|
switch (from)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
if (IP_BIT_ISSET(rtm->rtm_flags, IP_RTM_F_CLONED))
|
|
{
|
|
IP_BIT_CLR(rtm->rtm_flags, IP_RTM_F_CLONED);
|
|
rtm->rtm_type = IP_RTN_CLONE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipcom_netlink_rtnl_translate_link(int from, int to, struct Ip_nlmsghdr *nlh)
|
|
{
|
|
struct Ip_ifinfomsg *ifm = (struct Ip_ifinfomsg *)IP_NLMSG_DATA(nlh);
|
|
|
|
if (IP_NLMSG_PAYLOAD(nlh, 0) < sizeof(*ifm))
|
|
return;
|
|
|
|
ifm->ifi_change = ipcom_netlink_rtnl_translate_ifflags(from, to, ifm->ifi_change);
|
|
ifm->ifi_flags = ipcom_netlink_rtnl_translate_ifflags(from, to, ifm->ifi_flags);
|
|
|
|
if (from == IP_NETLINK_TRANSLATE_IPNET)
|
|
{
|
|
/* Switch from IPNET */
|
|
switch (to)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Switch to IPNET */
|
|
switch (from)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipcom_netlink_rtnl_translate_neigh(int from, int to, struct Ip_nlmsghdr *nlh)
|
|
{
|
|
struct Ip_ndmsg *ndm = (struct Ip_ndmsg *)IP_NLMSG_DATA(nlh);
|
|
|
|
if (IP_NLMSG_PAYLOAD(nlh, 0) < sizeof(*ndm))
|
|
return;
|
|
|
|
if (from == IP_NETLINK_TRANSLATE_IPNET)
|
|
{
|
|
/* Switch from IPNET */
|
|
switch (to)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
/* If they are set, they mean completely different things */
|
|
IP_BIT_CLR(ndm->ndm_flags, IP_NTF_GRAT|IP_NTF_EXTERNAL);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Switch to IPNET */
|
|
switch (from)
|
|
{
|
|
case IP_NETLINK_TRANSLATE_LINUX:
|
|
/* If they are set, they mean completely different things */
|
|
IP_BIT_CLR(ndm->ndm_flags, IP_NTF_GRAT|IP_NTF_EXTERNAL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* TRANSLATION FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_GLOBAL void
|
|
ipcom_netlink_rtnl_translate(int to, int from, struct Ip_nlmsghdr *nlh)
|
|
{
|
|
if (to == from)
|
|
return;
|
|
|
|
/* We cant deal with two unknowns, move one to IPNET */
|
|
if (IP_NETLINK_TRANSLATE_IPNET != from && to != IP_NETLINK_TRANSLATE_IPNET)
|
|
{
|
|
/* Translate one of them to IPNET - Its our base */
|
|
ipcom_netlink_rtnl_translate(from, IP_NETLINK_TRANSLATE_IPNET, nlh);
|
|
from = IP_NETLINK_TRANSLATE_IPNET;
|
|
}
|
|
|
|
ipcom_netlink_rtnl_translate_family(to, from, nlh);
|
|
|
|
if (IP_RTM_FAM(nlh->nlmsg_type) == IP_RTM_FAM(IP_RTM_NEWROUTE))
|
|
ipcom_netlink_rtnl_translate_route(to, from, nlh);
|
|
else if (IP_RTM_FAM(nlh->nlmsg_type) == IP_RTM_FAM(IP_RTM_NEWLINK))
|
|
ipcom_netlink_rtnl_translate_link(to, from, nlh);
|
|
else if (IP_RTM_FAM(nlh->nlmsg_type) == IP_RTM_FAM(IP_RTM_NEWNEIGH))
|
|
ipcom_netlink_rtnl_translate_neigh(to, from, nlh);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
IP_GLOBAL struct Ip_rtattr *
|
|
ipcom_netlink_addattr_l(struct Ip_nlmsghdr *n, Ip_size_t max_size, int type, const void *rta_data, Ip_size_t rta_len)
|
|
{
|
|
int rta_space = IP_RTA_LENGTH(rta_len);
|
|
struct Ip_rtattr *rta;
|
|
|
|
/* Have enough space? */
|
|
if (IP_NLMSG_ALIGN(n->nlmsg_len) + IP_RTA_ALIGN(rta_space) > (unsigned)max_size)
|
|
return IP_NULL;
|
|
|
|
/* Store the data */
|
|
rta = (struct Ip_rtattr *) ((char *)n + IP_NLMSG_ALIGN(n->nlmsg_len));
|
|
rta->rta_len = rta_space;
|
|
rta->rta_type = type;
|
|
|
|
if (IP_NULL != rta_data)
|
|
ipcom_memcpy(IP_RTA_DATA(rta), rta_data, rta_len);
|
|
|
|
/* Move the length indicator */
|
|
n->nlmsg_len = IP_NLMSG_ALIGN(n->nlmsg_len) + IP_RTA_ALIGN(rta_space);
|
|
return rta;
|
|
}
|
|
|
|
IP_GLOBAL struct Ip_rtattr *
|
|
ipcom_netlink_rta_addattr_l(struct Ip_rtattr *rta_nest, Ip_size_t max_size, int type, const void *rta_data, Ip_size_t rta_len)
|
|
{
|
|
struct Ip_rtattr *rta;
|
|
int rta_space = IP_RTA_LENGTH(rta_len);
|
|
|
|
if (IP_RTA_ALIGN(rta_nest->rta_len) + IP_RTA_ALIGN(rta_space) > max_size)
|
|
return IP_NULL;
|
|
|
|
rta = (struct Ip_rtattr*)(((char*)rta_nest) + IP_RTA_ALIGN(rta_nest->rta_len));
|
|
rta->rta_type = type;
|
|
rta->rta_len = rta_space;
|
|
|
|
if (IP_NULL != rta_data)
|
|
ipcom_memcpy(IP_RTA_DATA(rta), rta_data, rta_len);
|
|
rta_nest->rta_len = IP_NLMSG_ALIGN(rta_nest->rta_len) + IP_RTA_ALIGN(rta_space);
|
|
|
|
return rta;
|
|
}
|
|
|
|
IP_GLOBAL struct Ip_rtattr *
|
|
ipcom_netlink_addattr_l_begin(struct Ip_nlmsghdr *n, int max_size, int type)
|
|
{
|
|
int rta_space = IP_RTA_LENGTH(0);
|
|
struct Ip_rtattr *rta;
|
|
|
|
/* Have enough space? */
|
|
if (IP_NLMSG_ALIGN(n->nlmsg_len) + IP_RTA_ALIGN(rta_space) > (unsigned)max_size)
|
|
return IP_NULL;
|
|
|
|
/* Store the data */
|
|
rta = (struct Ip_rtattr *) ((char *)n + IP_NLMSG_ALIGN(n->nlmsg_len));
|
|
rta->rta_len = rta_space;
|
|
rta->rta_type = type;
|
|
return rta;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipcom_netlink_addattr_l_end(struct Ip_nlmsghdr *n, struct Ip_rtattr *rta)
|
|
{
|
|
n->nlmsg_len = IP_NLMSG_ALIGN(n->nlmsg_len) + IP_RTA_ALIGN(rta->rta_len);
|
|
}
|
|
|
|
IP_GLOBAL struct Ip_nlmsghdr *
|
|
ipcom_netlink_nlmsghdr_init(void *buf, int type, int flags, int hdrsize)
|
|
{
|
|
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)buf;
|
|
|
|
ipcom_memset(nlh, 0, sizeof(*nlh));
|
|
nlh->nlmsg_len = IP_NLMSG_LENGTH(hdrsize);
|
|
nlh->nlmsg_type = type;
|
|
nlh->nlmsg_flags = flags;
|
|
|
|
return nlh;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|