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

1132 lines
35 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_rtnetlink_link.c,v $ $Revision: 1.18.2.3 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_rtnetlink_link.c,v $
* $Author: hsun $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation Jonas Rendel <Jonas.Rendel@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* Contains netlink handlers for managing interfaces
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipnet_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPNET_USE_NETLINK
#define IPCOM_USE_CLIB_PROTO
#include <ipcom.h>
#include <ipcom_type.h>
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_sock2.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"
#ifdef IP_PORT_LKM
#include "ipcom_lkm.h" /* Needed for Linux PPP interface config */
#endif /* IP_PORT_LKM */
#ifdef IPMIP
#include <private/ipmip_netlink_kern.h>
#endif
#include "ipnet_eth.h"
#ifdef IPCOM_USE_FORWARDER_VLAN_STACKING
#include "ipnet_svlan_netlink.h"
#endif
#ifdef IPCOM_FORWARDER_NAE
#include <ipcom_forwarder.h>
#endif
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
#ifdef IPCOM_USE_TCP
IP_EXTERN IP_GLOBAL void
iptcp_ao_rtnetlink_init(void);
#endif
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC int
ipnet_rtnetlink_link_dump_all(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
int family,
Ip_ptrdiff_t *args)
{
Ip_ptrdiff_t *done = &args[0];
Ip_ptrdiff_t *cfamily = &args[1];
Ip_ptrdiff_t i;
Ipnet_rtnetlink_config_t *rtcfg = ipnet->netlink_data[IP_NETLINK_ROUTE];
(void)family;
for (i = *cfamily; i < IP_AF_MAX; i++)
{
Ipnet_rtnetlink_table_t **tbl;
if (i == IP_AF_PACKET || i == IP_AF_UNSPEC)
continue;
if ((tbl = rtcfg->family_event[i]) != IP_NULL)
{
/* Continue until termination */
if (tbl[nlmsg->nlmsg_type - IP_RTM_BASE] && tbl[nlmsg->nlmsg_type - IP_RTM_BASE]->nl_func_table.nl_dump)
{
(*tbl[nlmsg->nlmsg_type - IP_RTM_BASE]->nl_func_table.nl_dump) (mem, nlmsg, (int) i, &args[2]);
/* Done pointer */
if (!args[2])
goto exit_out;
}
}
/* Clear the args area */
ipcom_memset(&args[2], 0, sizeof(Ip_ptrdiff_t) * 6);
}
/* All done */
*done = 1;
exit_out:
*cfamily = i;
return (int) mem->used;
}
#ifdef IPNET_USE_NETLINKSOCK
/*
*===========================================================================
* ipnet_rtnetlink_link_stats_get
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipnet_rtnetlink_link_stats_retrieve(Ipnet_netif *netif,
struct Ip_rtnl_link_stats *devstats,
struct Ip_rtnl_link_stats64 *devstats64)
{
/* Map our internal statistics to the rtnl_link_stats */
ipcom_memset(devstats, 0, sizeof(*devstats));
devstats->rx_bytes = netif->ibytes;
devstats->rx_packets = netif->ipackets;
devstats->rx_errors = netif->ierrors;
devstats->rx_dropped = netif->iqdrops;
devstats->collisions = netif->collisions;
devstats->multicast = netif->imcasts;
devstats->tx_bytes = netif->obytes;
devstats->tx_packets = netif->opackets;
devstats->tx_errors = netif->oerrors;
ipcom_memset(devstats64, 0, sizeof(*devstats64));
devstats64->rx_bytes = netif->ibytes;
devstats64->rx_packets = netif->ipackets;
devstats64->rx_errors = netif->ierrors;
devstats64->rx_dropped = netif->iqdrops;
devstats64->collisions = netif->collisions;
devstats64->multicast = netif->imcasts;
devstats64->tx_bytes = netif->obytes;
devstats64->tx_packets = netif->opackets;
devstats64->tx_errors = netif->oerrors;
}
/*
*==========================================================================
* ipnet_rtnetlink_link_sz_fillifinfo
*===========================================================================
* Description: Get interface info via NETLINK
* Parameters: data - Message payload.
* len - Length of message.
* cb - NETLINK callback entry
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_STATIC int
ipnet_rtnetlink_link_sz_fillifinfo(Ipnet_netlink_mem_t *mem,
int event,
Ip_u16 eflags,
Ip_u32 seq,
Ip_u32 change,
Ipnet_netif *netif)
{
Ip_size_t ifname_len = ipcom_strlen(netif->ipcom.name);
struct Ip_ifinfomsg *ifinfo;
Ip_u32 tmp32;
struct Ip_nlmsghdr *nlh;
nlh = ipnet_netlink_nlmsg_sz_begin(mem, seq, event, eflags);
if (!nlh)
return -1;
/* Setup the IFINFO header */
ifinfo = ipnet_netlink_sz_put(mem, IP_NULL, sizeof(*ifinfo));
if (!ifinfo)
return -1;
ifinfo->ifi_family = IP_AF_UNSPEC;
ifinfo->ifi_type = (Ip_u16)IPCOM_ARPHRD_TYPE(&netif->ipcom);
ifinfo->ifi_index = (Ip_s32) netif->ipcom.ifindex;
ifinfo->ifi_flags = netif->ipcom.flags; /* Shouldn't this be mapped? */
ifinfo->ifi_change = change;
if (netif->ipcom.link_addr_size)
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_ADDRESS, netif->ipcom.link_addr_size, netif->ipcom.link_addr))
return -1;
/* Ethernet specific 'patch' */
if (ifinfo->ifi_type == IP_IFT_ETHER)
{
Ip_u16 bcast[3];
IPNET_SET_ETHADDR_BROADCAST(bcast);
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_BROADCAST, sizeof(bcast), bcast))
return -1;
#ifdef IPNET_USE_BOND
if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_SLAVE))
{
Ipnet_netif *master = ipnet_bond_get_master(netif);
if (master != IP_NULL)
{
tmp32 = master->ipcom.ifindex;
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_MASTER, sizeof(tmp32), &tmp32))
return -1;
}
}
#endif
}
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_IFNAME, ifname_len + 1, netif->ipcom.name))
return -1;
tmp32 = netif->ipcom.mtu;
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_MTU, sizeof(tmp32), &tmp32))
return -1;
tmp32 = netif->vr_index;
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_VR, sizeof(tmp32), &tmp32))
return -1;
if (IP_NULL != netif->snd_queue)
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_QDISC, ipcom_strlen(netif->snd_queue->type) + 1, netif->snd_queue->type))
return -1;
/* Do the statistics */
{
struct Ip_rtattr *rtas;
struct Ip_rtattr *rtas2;
rtas = ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_STATS, sizeof(struct Ip_rtnl_link_stats), IP_NULL);
if (!rtas)
return -1;
rtas2 = ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_STATS64, sizeof(struct Ip_rtnl_link_stats64), IP_NULL);
if (!rtas2)
return -1;
ipnet_rtnetlink_link_stats_retrieve(netif, (struct Ip_rtnl_link_stats *)IP_RTA_DATA(rtas), (struct Ip_rtnl_link_stats64 *)IP_RTA_DATA(rtas2));
}
if (netif->rtnetlink_ops != IP_NULL)
{
int ret;
struct Ip_rtattr *rta;
if (netif->rtnetlink_ops->fill_link)
{
ret = (*netif->rtnetlink_ops->fill_link) (mem, netif);
if (ret < 0)
return -1;
}
rta = ipnet_rtnetlink_rta_sz_nested_begin(mem, IP_IFLA_LINKINFO);
if (!rta)
return -1;
if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_INFO_KIND, ipcom_strlen(netif->rtnetlink_ops->kind) + 1, netif->rtnetlink_ops->kind))
return -1;
if (netif->rtnetlink_ops->fill_info != IP_NULL)
{
struct Ip_rtattr *info = ipnet_rtnetlink_rta_sz_nested_begin(mem, IP_IFLA_INFO_DATA);
if (!info)
return -1;
ret = (*netif->rtnetlink_ops->fill_info) (mem, netif);
if (ret < 0)
return -1;
ipnet_rtnetlink_rta_sz_nested_end(mem, info);
}
ipnet_rtnetlink_rta_sz_nested_end(mem, rta);
}
return ipnet_netlink_nlmsg_sz_end(mem, nlh);
}
/*
*==========================================================================
* ipnet_rtnetlink_link_dump
*===========================================================================
* Description: Get interface info via NETLINK
* Parameters: data - Message payload.
* len - Length of message.
* cb - NETLINK callback entry
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_STATIC int
ipnet_rtnetlink_link_dump_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
int family,
Ip_ptrdiff_t *args)
{
Ip_ptrdiff_t *done = &args[0];
Ip_ptrdiff_t *ifx = &args[1];
unsigned int i;
Ipnet_netif *netif;
Ip_u32 sindex = (Ip_u32) *ifx;
Ip_u16 vr = IPCOM_VR_ANY;
(void)family;
if (*done)
goto exit_out;
if (IP_BIT_ISFALSE(nlmsg->nlmsg_flags, IP_NLM_F_VR_UNSPEC) && (mem->vr != IPCOM_VR_ANY))
vr = mem->vr;
/*
* IPNET_NETIF_FOR_EACH_ON_VR sets netif to NULL after the for loop,
* this is a performance optimized defination
*/
/* coverity[result_independent_of_operands] */
IPNET_NETIF_FOR_EACH_ON_VR(netif, vr, i)
{
int ret;
if (sindex != 0 && sindex != netif->ipcom.ifindex)
continue;
sindex = 0;
*ifx = (Ip_ptrdiff_t) netif->ipcom.ifindex;
/* */
IPNET_IF_LOCK(netif);
ret = ipnet_rtnetlink_link_sz_fillifinfo(mem,
IP_RTM_NEWLINK,
IP_NLM_F_MULTI,
nlmsg->nlmsg_seq,
0,
netif);
IPNET_IF_UNLOCK(netif);
if (ret < 0)
goto exit_out;
}
/* We're done */
*done = 1;
exit_out:
return (int) mem->used;
}
IP_STATIC int
ipnet_rtnetlink_link_parse_linkops(struct Ip_rtattr **rta,
struct Ip_rtnl_link_ops **ops,
struct Ip_rtattr ***linkdata)
{
struct Ip_rtattr **linkinfo = IP_NULL;
int ret = 0;
if (rta[IP_IFLA_LINKINFO - 1] != IP_NULL)
{
char *kind;
/* Need the 'KIND*' */
ret = ipnet_netlink_parse(IP_IFLA_INFO_MAX, IP_RTA_DATA(rta[IP_IFLA_LINKINFO - 1]), IP_RTA_PAYLOAD(rta[IP_IFLA_LINKINFO - 1]), &linkinfo);
if (ret < 0)
goto done;
/* Got the linkinfo */
if ((kind = ipnet_netlink_strdup((struct Ip_nlattr *)linkinfo[IP_IFLA_INFO_KIND - 1])) != IP_NULL)
{
*ops = ipnet_rtnetlink_get_ops(kind);
ipcom_free(kind);
}
/* Parse link data, if we have it */
if (*ops != IP_NULL)
{
if ((*ops)->maxtype != 0 && linkinfo[IP_IFLA_INFO_DATA - 1] != IP_NULL)
{
ret = ipnet_netlink_parse((*ops)->maxtype, IP_RTA_DATA(linkinfo[IP_IFLA_INFO_DATA - 1]), IP_RTA_PAYLOAD(linkinfo[IP_IFLA_INFO_DATA - 1]), linkdata);
if (ret < 0)
goto done;
}
if ((*ops)->validate)
{
ret = (*(*ops)->validate) ( (struct Ip_nlattr**) rta, (struct Ip_nlattr**) linkdata);
if (ret < 0)
goto done;
}
}
}
done:
if (linkinfo)
ipcom_free(linkinfo);
return ret;
}
IP_STATIC int
ipnet_rtnetlink_link_setlink_family_linkops(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family,
struct Ip_rtnl_link_ops *ops,
struct Ip_rtattr **linkdata)
{
/**/
struct Ip_ifinfomsg *ifm;
char *ifname = IP_NULL;
Ipnet_netif *netif = IP_NULL;
struct Ip_ifreq ifreq;
int ret = 0;
Ip_u16 vr;
(void) family;
/* Copy or zero */
ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1]);
ifm = IP_NLMSG_DATA(nlmsg);
vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr);
if (ifm->ifi_index > 0)
netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index);
else if (ifname)
netif = ipnet_if_nametonetif(vr, ifname);
/* Didnt find the device? */
if (netif == IP_NULL)
{
ret = -IP_ERRNO_ENODEV;
goto done;
}
if (linkdata != IP_NULL && ops->changelink == IP_NULL)
{
ret = -IP_ERRNO_EOPNOTSUPP;
goto done;
}
ipcom_strcpy(ifreq.ifr_name, netif->ipcom.name);
/* Device address */
if (rta[IP_IFLA_ADDRESS - 1])
{
if (IP_RTA_PAYLOAD(rta[IP_IFLA_ADDRESS - 1]) != netif->ipcom.link_addr_size)
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
if (ipcom_memcmp(IP_RTA_DATA(rta[IP_IFLA_ADDRESS - 1]), netif->ipcom.link_addr, netif->ipcom.link_addr_size))
{
ipcom_memcpy(ifreq.ifr_ifru.ifru_addr.sa_data,
IP_RTA_DATA(rta[IP_IFLA_ADDRESS - 1]),
IP_RTA_PAYLOAD(rta[IP_IFLA_ADDRESS - 1]));
ret = ipnet_if_link_ioctl(netif, IP_SIOCSIFLLADDR, &ifreq);
if (ret < 0)
goto done;
IP_BIT_SET(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT);
}
}
#ifdef IPNET_USE_BOND
if ((IP_BIT_ISSET(ifm->ifi_flags, IP_IFF_SLAVE) && IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_SLAVE))
|| (IP_BIT_ISFALSE(ifm->ifi_flags, IP_IFF_SLAVE) && IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_SLAVE)))
{
/* Bonding operation */
if (IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_SLAVE))
{
/* Enslave this netif to an link aggregation */
if (rta[IP_IFLA_MASTER -1])
{
Ipnet_netif *master;
Ip_u32 ifindex;
ipcom_memcpy(&ifindex, IP_RTA_DATA(rta[IP_IFLA_MASTER - 1]), sizeof(Ip_u32));
master = ipnet_if_indextonetif(vr, ifindex);
if (master == IP_NULL)
{
/* Master interface not found */
ret = -IP_ERRNO_ENODEV;
goto done;
}
ret = ipnet_bond_if_enslave(master, netif);
if (ret < 0)
goto done;
}
else
{
/* Can not enslave without master */
ret = -IP_ERRNO_ENODEV;
goto done;
}
}
else
{
/* Release this netif from an link aggregation */
ret = ipnet_bond_if_release(netif);
if (ret < 0)
goto done;
}
}
#endif /* IPNET_USE_BOND */
if (rta[IP_IFLA_MTU - 1])
{
ifreq.ifr_ifru.ifru_mtu = (int) IP_GET_32ON8(IP_RTA_DATA(rta[IP_IFLA_MTU - 1]));
ret = ipnet_if_link_ioctl(netif, IP_SIOCSIFMTU, &ifreq);
if (ret == 0
|| ret == -IP_ERRNO_EOPNOTSUPP
|| ret == -IP_ERRNO_EINVAL)
{
/*
* ioctl either successful, or not supported by the link
* layer (IP_ERRNO_EOPNOSUPP) or by the driver
* (IP_ERRNO_EINVAL). The 2 errors are accepted since that
* is how setting the MTU used to work, i.e. no
* notification to the driver at all.
* The driver has to be notifed on VxWorks to enable
* Ethernet jumbograms (9k frames).
*/
if (netif->ipcom.mtu != (Ip_u32) ifreq.ifr_ifru.ifru_mtu)
{
netif->ipcom.mtu = (Ip_u32) ifreq.ifr_ifru.ifru_mtu;
/*
* Must flush the destination cache in order to
* handle the re-evaluation of path mtu properly
*/
ipnet_dst_cache_flush(netif->vr_index, 0);
IP_BIT_SET(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT);
}
ret = 0;
}
if (ret < 0)
goto done;
}
if (ifm->ifi_flags || ifm->ifi_change)
{
ret = ipnet_netif_change_flags(&netif, ifm->ifi_flags, ifm->ifi_change);
if (!netif)
goto done;
}
if (linkdata)
{
ret = (*ops->changelink) (netif, (struct Ip_nlattr**)rta, (struct Ip_nlattr**)linkdata);
if (ret < 0)
goto done;
}
if (IP_BIT_ISSET(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT))
ipnet_rtnetlink_link_change(netif);
done:
if (ifname)
ipcom_free(ifname);
return ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_link_setlink
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_rtnetlink_link_setlink_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
struct Ip_rtattr **linkdata = IP_NULL;
struct Ip_rtnl_link_ops *ops = IP_NULL;
int ret = 0;
if (0 > (ret = ipnet_rtnetlink_link_parse_linkops(rta, &ops, &linkdata)))
goto done;
ret = ipnet_rtnetlink_link_setlink_family_linkops(mem, nlmsg, rta, family, ops, linkdata);
done:
if (linkdata)
ipcom_free(linkdata);
return ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_link_setlink
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_rtnetlink_link_newlink_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
/**/
struct Ip_ifinfomsg *ifm;
char *ifname = IP_NULL;
Ipnet_netif *netif = IP_NULL;
struct Ip_rtattr **linkdata = IP_NULL;
int ret = 0;
struct Ip_rtnl_link_ops *ops = IP_NULL;
Ipnet_netif *nif = IP_NULL;
Ip_u16 vr;
/* Copy or zero */
ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1]);
ifm = IP_NLMSG_DATA(nlmsg);
vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr);
if (ifm->ifi_index > 0)
netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index);
else if (ifname)
netif = ipnet_if_nametonetif(vr, ifname);
if (0 > (ret = ipnet_rtnetlink_link_parse_linkops(rta, &ops, &linkdata)))
goto done;
/* Didnt find the device? */
if (netif != IP_NULL)
{
if (nlmsg->nlmsg_flags & IP_NLM_F_EXCL)
{
ret = -IP_ERRNO_EEXIST;
goto done;
}
if (nlmsg->nlmsg_flags & IP_NLM_F_REPLACE)
{
ret = -IP_ERRNO_EOPNOTSUPP;
goto done;
}
/* Do setlink */
ret = ipnet_rtnetlink_link_setlink_family_linkops(mem, nlmsg, rta, family, ops, linkdata);
}
else
{
if (ops == IP_NULL || ops->newlink == IP_NULL)
{
#ifdef IPCOM_FORWARDER_NAE
ops = ipnet_rtnetlink_get_ops("nae_shadow");
if (IP_NULL == ops)
{
ret = -IP_ERRNO_EOPNOTSUPP;
goto done;
}
#else
ret = -IP_ERRNO_EOPNOTSUPP;
goto done;
#endif
}
#ifndef IPCOM_FORWARDER_NAE
/* Control node has likely specified an interface index to use */
if (!(nlmsg->nlmsg_flags & IP_NLM_F_CREATE) || ifm->ifi_index)
{
ret = -IP_ERRNO_ENODEV;
goto done;
}
#endif
/* OK - We need to create the correct interface here */
nif = (Ipnet_netif *)ipcom_if_malloc(ops->ift_type);
if (!nif)
{
ret = -IP_ERRNO_ENOMEM;
goto done;
}
/**/
nif->vr_index = vr;
#if IPCOM_VR_MAX > 1
/* Must switch the effective VR - Or we'll fail config */
ipnet->effective_vr = vr;
#endif
#ifdef IPCOM_FORWARDER_NAE
/* Control node has specified an interface index to use */
if (ifm->ifi_index > 0)
nif->ipcom.ifindex = ifm->ifi_index;
#endif /* IPCOM_FORWARDER_NAE */
/* Find a valid interface name */
if (!ifname)
{
char tmpif[IP_IFNAMSIZ + 1];
int i;
/**/
for (i = 0; i < 1024; i++)
{
ipcom_snprintf(tmpif, sizeof(tmpif), "%s%d", ops->kind, i);
if (!ipnet_if_nametonetif(vr, tmpif))
{
ifname = ipcom_strdup(tmpif);
break;
}
}
}
if (!ifname)
{
ret = -IP_ERRNO_ENOMEM;
goto done;
}
/* Store name */
ipcom_strncpy(nif->ipcom.name, ifname, IP_IFNAMSIZ);
/* Do we have the setup callback? */
if (ops->setup)
{
/* We've gotten an interface; invoke setup routine */
(*ops->setup) (nif);
}
/* Store MTU, if specified */
if (rta[IP_IFLA_MTU - 1])
nif->ipcom.mtu = (Ip_u32) IP_GET_32ON8(IP_RTA_DATA(rta[IP_IFLA_MTU - 1]));
/* Successful creation? Dont allow the cleanup routine to destroy nif */
if ((ret = (*ops->newlink) (nif, (struct Ip_nlattr**)rta, (struct Ip_nlattr**)linkdata)) >= 0)
{
/* Do the extranous paramters, but no link ops */
ret = ipnet_rtnetlink_link_setlink_family_linkops(mem, nlmsg, rta, family, IP_NULL, IP_NULL);
nif = IP_NULL;
}
}
done:
if (ifname)
ipcom_free(ifname);
if (linkdata)
ipcom_free(linkdata);
if (nif)
IPNET_IF_UNLOCK(nif);
return ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_link_setlink
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_rtnetlink_link_getlink_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
/**/
struct Ip_ifinfomsg *ifm;
char *ifname = IP_NULL;
Ipnet_netif *netif = IP_NULL;
int ret = 0;
Ip_u16 vr;
(void)family;
ifm = IP_NLMSG_DATA(nlmsg);
vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr);
if (ifm->ifi_index > 0)
netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index);
else if ((ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1])) != IP_NULL)
netif = ipnet_if_nametonetif(vr, ifname);
/* Didnt find the device? */
if (netif == IP_NULL)
{
ret = -IP_ERRNO_ENODEV;
goto done;
}
/* */
IPNET_IF_LOCK(netif);
ret = ipnet_rtnetlink_link_sz_fillifinfo(mem,
IP_RTM_NEWLINK,
0,
nlmsg->nlmsg_seq,
0xFFFFFFFF,
netif);
IPNET_IF_UNLOCK(netif);
done:
if (ifname)
ipcom_free(ifname);
return ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_link_dellink_family
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipnet_rtnetlink_link_dellink_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
/**/
struct Ip_ifinfomsg *ifm;
char *ifname = IP_NULL;
Ipnet_netif *netif = IP_NULL;
int ret = 0;
Ip_u16 vr;
(void) family;
/* Copy or zero */
ifname = ipnet_netlink_strdup((struct Ip_nlattr *)rta[IP_IFLA_IFNAME - 1]);
ifm = IP_NLMSG_DATA(nlmsg);
vr = ipnet_rtnetlink_vr(rta[IP_IFLA_VR - 1], mem->vr);
if (ifm->ifi_index > 0)
netif = ipnet_if_indextonetif(vr, (Ip_u32) ifm->ifi_index);
else if (ifname)
netif = ipnet_if_nametonetif(vr, ifname);
/* Didnt find the device? */
if (netif == IP_NULL)
{
ret = -IP_ERRNO_ENODEV;
goto done;
}
if (netif->rtnetlink_ops == IP_NULL || netif->rtnetlink_ops->dellink == IP_NULL)
{
ret = -IP_ERRNO_EOPNOTSUPP;
goto done;
}
(*netif->rtnetlink_ops->dellink) (netif);
done:
if (ifname)
ipcom_free(ifname);
return ret;
}
#endif /* IPNET_USE_NETLINKSOCK */
/*
*===========================================================================
* ipnet_rtnetlink_link_if_change
*===========================================================================
* Description: Status of a network interface has changed, create a IFINFO
* event on NETLNK..
* Parameters: netif - The interface.
* Returns: -
*
*/
IP_STATIC void
ipnet_rtnetlink_link_if_event(Ipnet_netif *netif, int event)
{
#ifdef IPNET_USE_NETLINKSOCK
Ipcom_pkt *pkt = IP_NULL;
Ipnet_netlink_mem_t mem;
int ret;
if (!ipnet_netlink_pkt_alloc(&pkt, IP_NULL, IP_TRUE, &mem, 512))
return;
/* Must explicitly switch to the correct VR here */
pkt->vr_index = mem.vr = netif->vr_index;
ret = ipnet_rtnetlink_link_sz_fillifinfo(&mem,
event,
0,
0,
netif->rtnetlink_last_iflags ^ netif->ipcom.flags,
netif);
if (ret < 0)
ipcom_pkt_free(pkt);
else
{
pkt->end += ret;
IP_BIT_CLR(netif->flags2, IPNET_IFF2_RTNETLINK_EVENT);
/* Remember current link flags */
netif->rtnetlink_last_iflags = netif->ipcom.flags;
/* We're done; do report this pkt */
ipnet_rtnetlink_broadcast(pkt, IP_RTNLGRP_LINK);
}
#else
(void)netif;
#endif
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL void
ipnet_rtnetlink_link_change(struct Ipnet_netif_struct *netif)
{
ipnet_rtnetlink_link_if_event(netif, IP_RTM_NEWLINK);
}
IP_GLOBAL void
ipnet_rtnetlink_link_add(struct Ipnet_netif_struct *netif)
{
ipnet_rtnetlink_link_if_event(netif, IP_RTM_NEWLINK);
}
IP_GLOBAL void
ipnet_rtnetlink_link_delete(struct Ipnet_netif_struct *netif)
{
ipnet_rtnetlink_link_if_event(netif, IP_RTM_DELLINK);
}
IP_GLOBAL void
ipnet_rtnetlink_link_init(void)
{
#ifdef IPNET_USE_NETLINKSOCK
/* AF_UNSPEC */
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_DELLINK,
IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg),
ipnet_rtnetlink_link_dellink_family,
IP_NULL);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_NEWLINK,
IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg),
ipnet_rtnetlink_link_newlink_family,
IP_NULL);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_SETLINK,
IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg),
ipnet_rtnetlink_link_setlink_family,
IP_NULL);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETLINK,
IP_IFLA_MAX, sizeof(struct Ip_ifinfomsg),
ipnet_rtnetlink_link_getlink_family,
ipnet_rtnetlink_link_dump_family);
#endif /* IPNET_USE_NETLINKSOCK */
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETADDR,
IP_IFA_MAX, sizeof(struct Ip_ifaddrmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETMULTICAST,
IP_IFA_MAX, sizeof(struct Ip_ifaddrmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETANYCAST,
IP_IFA_MAX, sizeof(struct Ip_ifaddrmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETROUTE,
IP_RTA_MAX, sizeof(struct Ip_rtmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETRULE,
IP_RTA_MAX, sizeof(struct Ip_rtmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETNEIGH,
IP_NDA_MAX, sizeof(struct Ip_ndmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
#if defined(IPNET_USE_VLAN) && defined(IPNET_USE_NETLINKSOCK)
ipnet_vlan_rtnetlink_init();
#endif /* IPNET_USE_VLAN && IPNET_USE_NETLINKSOCK */
#if defined(IPNET_USE_BOND) && defined(IPNET_USE_NETLINKSOCK)
ipnet_bond_rtnetlink_init();
#endif /* IPNET_USE_VLAN && IPNET_USE_NETLINKSOCK */
#ifdef IPCOM_FORWARDER_NAE
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETFWCACHE,
IP_FWC_MAX, sizeof(struct Ip_fwcmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETNAE,
IP_NAE_MAX, sizeof(struct Ip_naemsg),
ipnet_rtnetlink_nae_getnae_family,
IP_NULL);
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_SETNAE,
IP_NAE_MAX, sizeof(struct Ip_naemsg),
ipnet_rtnetlink_nae_setnae_family,
IP_NULL);
ipnet_nae_rtnetlink_init();
#endif
#ifdef IPCOM_USE_FORWARDER_IPSEC
ipnet_rtnetlink_register_family_event(IP_AF_UNSPEC, IP_RTM_GETSACACHE,
IP_SAC_MAX, sizeof(struct Ip_sacmsg),
IP_NULL,
ipnet_rtnetlink_link_dump_all);
#endif
/* Init the neigh module */
ipnet_rtnetlink_vr_init();
#ifdef IPMIP
ipmip_rtnetlink_init();
#endif
#ifdef IPCOM_USE_FORWARDER_VLAN_STACKING
/* register VLAN stacking netlink msg handler */
ipnet_svlan_rtnetlink_init();
#endif
#ifdef IPCOM_USE_TCP
iptcp_ao_rtnetlink_init();
#endif
}
#endif /* IPNET_USE_NETLINK */
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/