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

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
****************************************************************************
*/