1132 lines
35 KiB
C
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
|
|
****************************************************************************
|
|
*/
|