2039 lines
55 KiB
C
2039 lines
55 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_cmd_ip.c,v $ $Revision: 1.5.8.3 $
|
|
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_cmd_ip.c,v $
|
|
* $Author: hxie $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPCOM_KERNEL
|
|
#undef IPCOM_KERNEL
|
|
#endif
|
|
#include "ipnet_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_getopt.h>
|
|
#include <ipcom_shell.h>
|
|
#include <ipcom_sysctl.h>
|
|
|
|
#include "ipnet.h"
|
|
#include "ipnet_cmd.h"
|
|
#include "ipnet_ctrl.h"
|
|
#include "ipnet_h.h"
|
|
#include "ipnet_sysctl.h"
|
|
|
|
#include "ipnet_cmd_ip.h"
|
|
#include "ipcom_sock.h"
|
|
|
|
#ifdef IPNET_USE_NETLINK
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
enum
|
|
{
|
|
IPNET_IP_MAIN_ARG_VR,
|
|
IPNET_IP_MAIN_ARG_FAMILY_X,
|
|
IPNET_IP_MAIN_ARG_FAMILY_PACKET,
|
|
IPNET_IP_MAIN_ARG_FAMILY_INET,
|
|
IPNET_IP_MAIN_ARG_FAMILY_INET6,
|
|
IPNET_IP_MAIN_ARG_ONELINE,
|
|
IPNET_IP_MAIN_ARG_SHOW_DETAILS,
|
|
IPNET_IP_MAIN_ARG_SHOW_STATS,
|
|
IPNET_IP_MAIN_ARG_SILENT,
|
|
IPNET_IP_MAIN_ARG_CORE,
|
|
IPNET_IP_MAIN_ARG_HELP,
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
static Ipcom_cmd_int_str_map ipnet_ip_module[] =
|
|
{
|
|
{ IPNET_IP_MODULE_ROUTE, "route" },
|
|
{ IPNET_IP_MODULE_NEIGH, "neigh" },
|
|
{ IPNET_IP_MODULE_NEIGH, "neighbor" },
|
|
{ IPNET_IP_MODULE_NEIGH, "neighbour" },
|
|
{ IPNET_IP_MODULE_RULE, "rule" },
|
|
{ IPNET_IP_MODULE_LINK, "link" },
|
|
{ IPNET_IP_MODULE_TUNNEL, "tunnel" },
|
|
{ IPNET_IP_MODULE_ADDRESS, "address" },
|
|
{ IPNET_IP_MODULE_ADDRESS, "addr" },
|
|
{ IPNET_IP_MODULE_VR, "vr" },
|
|
{ IPNET_IP_MODULE_XFRM, "xfrm" },
|
|
{ IPNET_IP_MODULE_MONITOR, "monitor" },
|
|
{ IPNET_IP_MODULE_ALL, "all" },
|
|
{ IPNET_IP_MODULE_FLUSH, "flush" },
|
|
{ IPNET_IP_MODULE_HELP, "help" },
|
|
#ifdef IPCOM_FORWARDER_NAE
|
|
{ IPNET_IP_MODULE_FWC, "fwc" },
|
|
{ IPNET_IP_MODULE_FWC, "fwcache" },
|
|
{ IPNET_IP_MODULE_NAE, "nae" },
|
|
#endif
|
|
#ifdef IPCOM_USE_FORWARDER_IPSEC
|
|
{ IPNET_IP_MODULE_SAC, "sac" },
|
|
{ IPNET_IP_MODULE_SAC, "sacache" },
|
|
#endif
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
static Ipcom_cmd_int_str_map ipnet_ip_main[] =
|
|
{
|
|
{ IPNET_IP_MAIN_ARG_VR, "-V" },
|
|
{ IPNET_IP_MAIN_ARG_FAMILY_X, "-family" },
|
|
{ IPNET_IP_MAIN_ARG_FAMILY_X, "-f" },
|
|
{ IPNET_IP_MAIN_ARG_FAMILY_PACKET, "-0" },
|
|
#ifdef IPCOM_USE_INET
|
|
{ IPNET_IP_MAIN_ARG_FAMILY_INET, "-4" },
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
{ IPNET_IP_MAIN_ARG_FAMILY_INET6, "-6" },
|
|
#endif
|
|
{ IPNET_IP_MAIN_ARG_ONELINE, "-oneline" },
|
|
{ IPNET_IP_MAIN_ARG_ONELINE, "-o" },
|
|
{ IPNET_IP_MAIN_ARG_SHOW_DETAILS, "-details" },
|
|
{ IPNET_IP_MAIN_ARG_SHOW_DETAILS, "-d" },
|
|
{ IPNET_IP_MAIN_ARG_SHOW_STATS, "-statistics" },
|
|
{ IPNET_IP_MAIN_ARG_SHOW_STATS, "-s" },
|
|
{ IPNET_IP_MAIN_ARG_CORE, "-core" },
|
|
{ IPNET_IP_MAIN_ARG_CORE, "-c" },
|
|
{ IPNET_IP_MAIN_ARG_SILENT, "-silent" },
|
|
{ IPNET_IP_MAIN_ARG_HELP, "-help" },
|
|
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
static Ipcom_cmd_int_str_map ipnet_ip_main_family[] =
|
|
{
|
|
{ IP_AF_PACKET, "link" },
|
|
#ifdef IPCOM_USE_INET
|
|
{ IP_AF_INET, "inet" },
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
{ IP_AF_INET6, "inet6" },
|
|
#endif
|
|
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
Ipcom_cmd_int_str_map ipnet_ip_default_values[] =
|
|
{
|
|
{ 0, "any" },
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
Ipcom_cmd_int_str_map ipnet_ip_core_values[] =
|
|
{
|
|
{ -1, "any" },
|
|
{ -1, "all" },
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
Ipcom_cmd_int_str_map ipnet_ip_vr_values[] =
|
|
{
|
|
{ IPCOM_VR_ANY, "any" },
|
|
{ IPCOM_VR_ANY, "all" },
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
Ipcom_cmd_int_str_map ipnet_ip_onoff_values[] =
|
|
{
|
|
{ 0, "off" },
|
|
{ 1, "on" },
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
Ipcom_cmd_int_str_map ipnet_ip_proto_values[] =
|
|
{
|
|
{ 0, "any" },
|
|
{ IP_IPPROTO_ICMP, "icmp" },
|
|
{ IP_IPPROTO_IGMP, "igmp" },
|
|
{ IP_IPPROTO_IPIP, "ipip" },
|
|
{ IP_IPPROTO_IPIP, "ip4" },
|
|
{ IP_IPPROTO_IPIP, "ipv4" },
|
|
{ IP_IPPROTO_IPV6, "ip6" },
|
|
{ IP_IPPROTO_IPV6, "ipv6" },
|
|
{ IP_IPPROTO_RSVP, "rsvp" },
|
|
{ IP_IPPROTO_GRE, "gre" },
|
|
{ IP_IPPROTO_ESP, "esp" },
|
|
{ IP_IPPROTO_AH, "ah" },
|
|
{ IP_IPPROTO_MOBILE, "mobile" },
|
|
{ IP_IPPROTO_MOBILE, "minenc" },
|
|
{ IP_IPPROTO_MOBILE, "minenc" },
|
|
{ IP_IPPROTO_ICMPV6, "icmpv6" },
|
|
{ IP_IPPROTO_NONEXTHDR, "nonexthdr" },
|
|
{ IP_IPPROTO_OSPFIGP, "ospfigp" },
|
|
{ IP_IPPROTO_OSPFIGP, "ospf" },
|
|
{ IP_IPPROTO_PIM, "pim" },
|
|
{ IP_IPPROTO_L2TP, "l2tp" },
|
|
{ IP_IPPROTO_SCTP, "sctp" },
|
|
{ IP_IPPROTO_MH, "mh" },
|
|
{ IP_IPPROTO_UDPLITE, "udplite" },
|
|
{ IP_IPPROTO_TCP, "tcp" },
|
|
{ IP_IPPROTO_UDP, "udp" },
|
|
{ -1, IP_NULL },
|
|
};
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* IP TOOL FLUSH MODULE
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_cmd_ip_flush_usage(Ipnet_ip_config_t *cfg, int ret)
|
|
{
|
|
int i;
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, "NAME"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " ip flush - Flush states belonging to module(s)"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, "SYNOPSIS"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " ip flush");
|
|
for (i = 0; i < IPNET_IP_MODULE_MAX; i++)
|
|
ipnet_ip_stdio_printf(cfg, " [%s]", ipnet_ip_key_to_str(ipnet_ip_module, i , IP_NULL, 0));
|
|
ipnet_ip_stdio_printf(cfg, " [all]"IP_LF);
|
|
return ret;
|
|
}
|
|
|
|
IP_STATIC Ip_ssize_t
|
|
ipnet_cmd_ip_module_flush_internal(Ipnet_ip_config_t *cfg)
|
|
{
|
|
char *sarg;
|
|
int arg;
|
|
Ip_u32 modules = 0;
|
|
|
|
while (IP_FALSE != ipnet_ip_cmd_param_str(&sarg, cfg))
|
|
{
|
|
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_module, sarg))
|
|
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
|
|
|
|
switch (arg)
|
|
{
|
|
case IPNET_IP_MODULE_HELP:
|
|
return ipnet_cmd_ip_flush_usage(cfg, 0);
|
|
case IPNET_IP_MODULE_ALL:
|
|
for (arg = 0; arg < IPNET_IP_MODULE_MAX; arg++)
|
|
modules |= IP_BIT_UVAL(arg);
|
|
break;
|
|
default:
|
|
modules |= IP_BIT_UVAL(arg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (modules == 0)
|
|
{
|
|
for (arg = 0; arg < IPNET_IP_MODULE_MAX; arg++)
|
|
modules |= IP_BIT_UVAL(arg);
|
|
}
|
|
|
|
return ipnet_cmd_ip_module_flush(cfg, modules);
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* IP TOOL MONITOR MODULE
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_cmd_ip_monitor_usage(Ipnet_ip_config_t *cfg, int ret)
|
|
{
|
|
int i;
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, "NAME"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " ip monitor - Monitor changes done to the IPNET stack"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, "SYNOPSIS"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " ip monitor");
|
|
for (i = 0; i < IPNET_IP_MODULE_MAX; i++)
|
|
ipnet_ip_stdio_printf(cfg, " [%s]", ipnet_ip_key_to_str(ipnet_ip_module, i , IP_NULL, 0));
|
|
ipnet_ip_stdio_printf(cfg, " [all]"IP_LF);
|
|
return ret;
|
|
}
|
|
|
|
IP_STATIC Ip_ssize_t
|
|
ipnet_cmd_ip_module_monitor_internal(Ipnet_ip_config_t *cfg)
|
|
{
|
|
char *sarg;
|
|
int arg;
|
|
Ip_u32 modules = 0;
|
|
|
|
while (IP_FALSE != ipnet_ip_cmd_param_str(&sarg, cfg))
|
|
{
|
|
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_module, sarg))
|
|
return ipnet_cmd_ip_unknown_keyword(cfg, sarg);
|
|
|
|
switch (arg)
|
|
{
|
|
case IPNET_IP_MODULE_HELP:
|
|
return ipnet_cmd_ip_monitor_usage(cfg, 0);
|
|
case IPNET_IP_MODULE_ALL:
|
|
for (arg = 0; arg < IPNET_IP_MODULE_MAX; arg++)
|
|
modules |= IP_BIT_UVAL(arg);
|
|
break;
|
|
default:
|
|
modules |= IP_BIT_UVAL(arg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (modules == 0)
|
|
{
|
|
for (arg = 0; arg < IPNET_IP_MODULE_MAX; arg++)
|
|
modules |= IP_BIT_UVAL(arg);
|
|
}
|
|
|
|
return ipnet_cmd_ip_module_monitor(cfg, modules);
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* IP TOOL MODULE
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_cmd_ip_usage(Ipnet_ip_config_t *cfg, int ret)
|
|
{
|
|
char *inet_short = "4";
|
|
char *inet_long = "inet|";
|
|
char *inet6_short = "6";
|
|
char *inet6_long = "inet6|";
|
|
int i;
|
|
|
|
#ifndef IPCOM_USE_INET
|
|
inet_short = "";
|
|
inet_long = "";
|
|
#endif
|
|
|
|
#ifndef IPCOM_USE_INET6
|
|
inet6_short = "";
|
|
inet6_long = "";
|
|
#endif
|
|
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, "NAME"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " ip - Display and modify the IPNET networking states and configurations"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, "SYNOPSIS"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " ip [-%s%s0] [-V <vr>] [-family <%s%slink>] [-help]"IP_LF, inet_short, inet6_short, inet_long, inet6_long);
|
|
ipnet_ip_stdio_printf(cfg, " ");
|
|
for (i = 0; i < IPNET_IP_MODULE_MAX; i++)
|
|
ipnet_ip_stdio_printf(cfg, " [%s]", ipnet_ip_key_to_str(ipnet_ip_module, i , IP_NULL, 0));
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, ""IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, "DESCRIPTION"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " -0 Use AF_PACKET family"IP_LF);
|
|
#ifdef IPCOM_USE_INET
|
|
ipnet_ip_stdio_printf(cfg, " -4 Use AF_INET family"IP_LF);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
ipnet_ip_stdio_printf(cfg, " -6 Use AF_INET6 family"IP_LF);
|
|
#endif
|
|
ipnet_ip_stdio_printf(cfg, " -family <%s%slink>"IP_LF, inet_long, inet6_long);
|
|
ipnet_ip_stdio_printf(cfg, " Switch to the family specified by the argument:"IP_LF);
|
|
ipnet_ip_stdio_printf(cfg, " link - AF_PACKET"IP_LF);
|
|
#ifdef IPCOM_USE_INET
|
|
ipnet_ip_stdio_printf(cfg, " inet - AF_INET"IP_LF);
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
ipnet_ip_stdio_printf(cfg, " inet6 - AF_INET6"IP_LF);
|
|
#endif
|
|
#if IPCOM_VR_MAX > 1
|
|
ipnet_ip_stdio_printf(cfg, " -V <vr> Switch to Virtual Router <vr>"IP_LF);
|
|
#endif
|
|
ipnet_ip_stdio_printf(cfg, " -help Display usage information"IP_LF);
|
|
|
|
return ret;
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipnet_cmd_ip_internal_init(Ipnet_ip_config_t *cfg, int argc, char **argv)
|
|
{
|
|
ipcom_memset(cfg, 0, sizeof(*cfg));
|
|
|
|
cfg->argc = argc;
|
|
cfg->argv = argv;
|
|
cfg->pos = 0;
|
|
cfg->family = IP_AF_UNSPEC;
|
|
cfg->oneline = IP_LF;
|
|
|
|
cfg->vr = (Ip_u16) ipcom_proc_vr_get();
|
|
cfg->orig_vr = cfg->vr;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* IP TOOL LIBRARY ROUTINES
|
|
****************************************************************************
|
|
*/
|
|
IP_GLOBAL Ipnet_ip_handle_msg_t *
|
|
ipnet_ip_alloc_reply(Ip_size_t nlh_len)
|
|
{
|
|
Ipnet_ip_handle_msg_t *msg = ipcom_calloc(1, sizeof(Ipnet_ip_handle_msg_t) + nlh_len);
|
|
|
|
if (IP_NULL != msg)
|
|
msg->hdr = (void *)(msg + 1);
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
|
|
IP_GLOBAL const char *
|
|
ipnet_ip_rta_str(struct Ip_rtattr *rta)
|
|
{
|
|
return (const char *)IP_RTA_DATA(rta);
|
|
}
|
|
|
|
IP_GLOBAL Ip_u64
|
|
ipnet_ip_rta_u64(struct Ip_rtattr *rta)
|
|
{
|
|
Ip_u64 tmp64;
|
|
ipcom_memcpy(&tmp64, IP_RTA_DATA(rta), sizeof(tmp64));
|
|
return tmp64;
|
|
}
|
|
|
|
IP_GLOBAL Ip_u32
|
|
ipnet_ip_rta_u32(struct Ip_rtattr *rta)
|
|
{
|
|
return IP_GET_32ON8(IP_RTA_DATA(rta));
|
|
}
|
|
|
|
IP_GLOBAL Ip_s32
|
|
ipnet_ip_rta_s32(struct Ip_rtattr *rta)
|
|
{
|
|
return (Ip_s32)ipnet_ip_rta_u32(rta);
|
|
}
|
|
|
|
IP_GLOBAL Ip_u16
|
|
ipnet_ip_rta_u16(struct Ip_rtattr *rta)
|
|
{
|
|
Ip_u16 u16;
|
|
|
|
ipcom_memcpy(&u16, IP_RTA_DATA(rta), sizeof(u16));
|
|
return u16;
|
|
}
|
|
|
|
IP_GLOBAL Ip_s16
|
|
ipnet_ip_rta_s16(struct Ip_rtattr *rta)
|
|
{
|
|
return (Ip_s16)ipnet_ip_rta_u32(rta);
|
|
}
|
|
|
|
IP_GLOBAL void*
|
|
ipnet_ip_rta_data_safe(struct Ip_rtattr *rta)
|
|
{
|
|
if (IP_NULL == rta)
|
|
return IP_NULL;
|
|
return IP_RTA_DATA(rta);
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipnet_ip_rta_vr(Ipnet_ip_config_t *cfg, struct Ip_rtattr *rta)
|
|
{
|
|
if (IP_NULL == rta)
|
|
return cfg->vr;
|
|
return ipnet_ip_rta_s32(rta);
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_parse_attr(struct Ip_rtattr **rta, Ip_size_t rta_max, struct Ip_rtattr *attr, Ip_size_t attrlen)
|
|
{
|
|
ipcom_memset(rta, 0, sizeof(struct Ip_rtattr *) * (rta_max + 1));
|
|
while (IP_RTA_OK(attr, attrlen))
|
|
{
|
|
if (attr->rta_type)
|
|
{
|
|
if (attr->rta_type <= rta_max)
|
|
rta[attr->rta_type] = attr;
|
|
}
|
|
|
|
attr = IP_RTA_NEXT(attr, attrlen);
|
|
}
|
|
}
|
|
|
|
|
|
IP_GLOBAL int
|
|
ipnet_ip_parse_reply(Ipnet_ip_handle_msg_t *msg, Ip_size_t rta_max, Ip_size_t priv_hdr)
|
|
{
|
|
Ip_size_t min_size = IP_NLMSG_LENGTH(priv_hdr);
|
|
struct Ip_rtattr *attr = (struct Ip_rtattr*)((char *)msg->hdr + IP_NLMSG_ALIGN(min_size));
|
|
Ip_size_t attrlen = msg->hdr->nlmsg_len - IP_NLMSG_ALIGN(min_size);
|
|
|
|
if (IP_NULL != msg->rta)
|
|
return 0;
|
|
|
|
msg->rta = ipcom_malloc(sizeof(struct Ip_rtattr *) * (rta_max + 1));
|
|
|
|
if (IP_NULL == msg->rta)
|
|
return -IP_ERRNO_ENOMEM;
|
|
|
|
ipnet_ip_parse_attr(msg->rta, rta_max, attr, attrlen);
|
|
return 0;
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_size_t
|
|
ipnet_ip_parse_rta_array_attr(struct Ip_rtattr **rta, int rta_type, struct Ip_rtattr *attr, Ip_size_t attrlen)
|
|
{
|
|
Ip_size_t count = 0;
|
|
while (IP_RTA_OK(attr, attrlen))
|
|
{
|
|
if (rta_type == attr->rta_type)
|
|
{
|
|
if (IP_NULL != rta)
|
|
rta[count] = attr;
|
|
count++;
|
|
}
|
|
attr = IP_RTA_NEXT(attr, attrlen);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
IP_GLOBAL struct Ip_rtattr **
|
|
ipnet_ip_parse_rta_array_nested(struct Ip_rtattr *rta_nest, int rta_type)
|
|
{
|
|
struct Ip_rtattr *attr = IP_RTA_DATA(rta_nest);
|
|
Ip_size_t attrlen = IP_RTA_PAYLOAD(rta_nest);
|
|
Ip_size_t count = ipnet_ip_parse_rta_array_attr(IP_NULL, rta_type, attr, attrlen);
|
|
struct Ip_rtattr **rta = IP_NULL;
|
|
|
|
if (0 != count)
|
|
{
|
|
rta = ipcom_calloc(count + 1, sizeof(*rta));
|
|
if (IP_NULL != rta)
|
|
(void)ipnet_ip_parse_rta_array_attr(rta, rta_type, attr, attrlen);
|
|
}
|
|
|
|
return rta;
|
|
}
|
|
|
|
IP_GLOBAL struct Ip_rtattr **
|
|
ipnet_ip_parse_rta_array(Ipnet_ip_handle_msg_t *msg, int rta_type, Ip_size_t priv_hdr)
|
|
{
|
|
Ip_size_t min_size = IP_NLMSG_LENGTH(priv_hdr);
|
|
struct Ip_rtattr *attr = (struct Ip_rtattr*)((char *)msg->hdr + IP_NLMSG_ALIGN(min_size));
|
|
Ip_size_t attrlen = msg->hdr->nlmsg_len - IP_NLMSG_ALIGN(min_size);
|
|
Ip_size_t count = ipnet_ip_parse_rta_array_attr(IP_NULL, rta_type, attr, attrlen);
|
|
struct Ip_rtattr **rta = IP_NULL;
|
|
|
|
if (0 != count)
|
|
{
|
|
rta = ipcom_calloc(count + 1, sizeof(*rta));
|
|
if (IP_NULL != rta)
|
|
(void)ipnet_ip_parse_rta_array_attr(rta, rta_type, attr, attrlen);
|
|
}
|
|
|
|
return rta;
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_free_reply(Ipnet_ip_handle_msg_t *msg)
|
|
{
|
|
if (msg->next.head != IP_NULL)
|
|
ipcom_list_remove(&msg->next);
|
|
|
|
if (msg->rta)
|
|
ipcom_free(msg->rta);
|
|
ipcom_free(msg);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_free_replies(Ipcom_list *replies)
|
|
{
|
|
Ipnet_ip_handle_msg_t *msg;
|
|
|
|
while (IP_NULL != (msg = IPCOM_LIST_FIRST(replies)))
|
|
ipnet_ip_free_reply(msg);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_copy_replies(Ipcom_list *head, Ipnet_ip_handle_t *handle)
|
|
{
|
|
Ipnet_ip_handle_msg_t *msg;
|
|
|
|
ipcom_list_init(head);
|
|
while (IP_NULL != (msg = IPCOM_LIST_FIRST(&handle->replies)))
|
|
{
|
|
ipcom_list_remove(&msg->next);
|
|
ipcom_list_insert_last(head, &msg->next);
|
|
}
|
|
}
|
|
|
|
#if defined(IPCOM_FORWARDER_NAE)
|
|
IP_STATIC void
|
|
ipnet_ip_event_netlink(struct Ipcom_socket_struct *sock, IP_CONST Ipcom_pkt *pkt, enum Ipcom_socket_event_type event)
|
|
{
|
|
int val = pkt->end - pkt->start;
|
|
Ipnet_ip_handle_t *handle = (Ipnet_ip_handle_t *)sock->cookie;
|
|
|
|
(void) event;
|
|
if (IP_NULL != handle && IP_NULL != pkt)
|
|
{
|
|
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&pkt->data[pkt->start];
|
|
|
|
while (IP_NLMSG_OK(nlh, (unsigned)val))
|
|
{
|
|
Ipnet_ip_handle_msg_t *nlmsg;
|
|
|
|
/* Append this NLH */
|
|
nlmsg = ipnet_ip_alloc_reply(nlh->nlmsg_len);
|
|
if (IP_NULL == nlmsg)
|
|
return;
|
|
|
|
/* We are locked here */
|
|
ipcom_memcpy(nlmsg->hdr, nlh, nlh->nlmsg_len);
|
|
ipcom_list_insert_last(&handle->inqueue, &nlmsg->next);
|
|
|
|
/* Notify */
|
|
ipcom_sem_post(handle->inqueue_sem);
|
|
nlh = IP_NLMSG_NEXT(nlh, val);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
IP_GLOBAL Ipnet_ip_handle_t *
|
|
ipnet_ip_open_netlink(Ipnet_ip_config_t *cfg, Ip_u32 groups, Ip_u8 proto)
|
|
{
|
|
Ipnet_ip_handle_t *handle = ipcom_calloc(1, sizeof(*handle));
|
|
|
|
if (IP_NULL != handle)
|
|
{
|
|
/* */
|
|
#if defined(IPCOM_FORWARDER_NAE)
|
|
ipcom_list_init(&handle->replies);
|
|
ipcom_list_init(&handle->inqueue);
|
|
ipcom_sem_create(&handle->inqueue_sem, 0);
|
|
handle->nae_sock = ipcom_netlink_nae_socket_open(cfg->vr, proto, 0, groups, &handle->src, (Ipcom_socket_eventcb)ipnet_ip_event_netlink, handle);
|
|
if (IP_NULL == handle->nae_sock)
|
|
{
|
|
ipnet_ip_close_netlink(handle);
|
|
return IP_NULL;
|
|
}
|
|
#else
|
|
Ip_socklen_t len;
|
|
int val;
|
|
|
|
ipcom_list_init(&handle->replies);
|
|
handle->fd = ipcom_socket(IP_AF_NETLINK, IP_SOCK_RAW, proto);
|
|
if (IP_INVALID_SOCKET == handle->fd)
|
|
{
|
|
ipnet_ip_close_netlink(handle);
|
|
return IP_NULL;
|
|
}
|
|
|
|
val = IPNET_IP_HANDLE_BUFFER;
|
|
if (0 > ipcom_setsockopt(handle->fd, IP_SOL_SOCKET, IP_SO_SNDBUF, &val, sizeof(val)) ||
|
|
0 > ipcom_setsockopt(handle->fd, IP_SOL_SOCKET, IP_SO_RCVBUF, &val, sizeof(val)))
|
|
{
|
|
ipnet_ip_close_netlink(handle);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/** Special case for wildcard VR */
|
|
if (cfg->vr == IPCOM_VR_ANY)
|
|
{
|
|
val = IPCOM_VR_ANY;
|
|
if (0 > ipcom_setsockopt(handle->fd, IP_SOL_SOCKET, IP_SO_X_VR, &val, sizeof(val)))
|
|
{
|
|
ipnet_ip_close_netlink(handle);
|
|
return IP_NULL;
|
|
}
|
|
}
|
|
|
|
handle->src.nl_family = IP_AF_NETLINK;
|
|
IPCOM_SA_LEN_SET(&handle->src, sizeof(handle->src));
|
|
handle->src.nl_groups = groups;
|
|
|
|
/* Bind socket */
|
|
len = sizeof(handle->src);
|
|
if (0 > ipcom_bind(handle->fd, (struct Ip_sockaddr *)&handle->src, len) ||
|
|
0 > ipcom_getsockname(handle->fd, (struct Ip_sockaddr *)&handle->src, &len))
|
|
{
|
|
ipnet_ip_close_netlink(handle);
|
|
return IP_NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_close_netlink(Ipnet_ip_handle_t *handle)
|
|
{
|
|
if (IP_NULL != handle)
|
|
{
|
|
/* Free any stored replies */
|
|
ipnet_ip_free_replies(&handle->replies);
|
|
|
|
/* Close the socket */
|
|
#if defined(IPCOM_FORWARDER_NAE)
|
|
if (IP_NULL != handle->nae_sock)
|
|
ipcom_netlink_nae_socket_close(handle->nae_sock);
|
|
ipcom_sem_delete(&handle->inqueue_sem);
|
|
ipnet_ip_free_replies(&handle->inqueue);
|
|
#else
|
|
if (IP_INVALID_SOCKET != handle->fd)
|
|
ipcom_socketclose(handle->fd);
|
|
#endif
|
|
|
|
/* Free the handle */
|
|
ipcom_free(handle);
|
|
}
|
|
}
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_ip_send_netlink(Ipnet_ip_handle_t *handle, struct Ip_nlmsghdr *nlh, int core)
|
|
{
|
|
struct Ip_sockaddr_nl nladdr;
|
|
struct Ip_iovec vec;
|
|
struct Ip_msghdr msg;
|
|
|
|
ipcom_memset(&nladdr, 0, sizeof(nladdr));
|
|
nladdr.nl_family = IP_AF_NETLINK;
|
|
IPCOM_SA_LEN_SET(&nladdr, sizeof(nladdr));
|
|
|
|
/* Specify buffer */
|
|
nlh = nlh? nlh : (struct Ip_nlmsghdr*) &handle->tx[0];
|
|
|
|
ipcom_memset(&msg, 0, sizeof(msg));
|
|
msg.msg_name = &nladdr;
|
|
msg.msg_namelen = sizeof(nladdr);
|
|
msg.msg_iov = &vec;
|
|
msg.msg_iovlen = 1;
|
|
|
|
vec.iov_base = nlh;
|
|
vec.iov_len = nlh->nlmsg_len;
|
|
|
|
#if defined(IPCOM_FORWARDER_NAE)
|
|
{
|
|
Ip_ssize_t ret;
|
|
if (0 > (ret = ipcom_netlink_nae_socket_send(core, handle->nae_sock, &msg)))
|
|
return ret;
|
|
}
|
|
#else
|
|
(void) core;
|
|
if (0 > ipcom_sendmsg(handle->fd, &msg, 0))
|
|
return (Ip_ssize_t)-ipcom_errno;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_ip_recv_netlink(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_t *handle)
|
|
{
|
|
#if defined(IPCOM_FORWARDER_NAE)
|
|
for (;;)
|
|
{
|
|
Ipnet_ip_handle_msg_t *nlmsg;
|
|
|
|
ipcom_sem_wait(handle->inqueue_sem);
|
|
ipcom_netlink_nae_socket_lock(handle->nae_sock);
|
|
nlmsg = IPCOM_LIST_FIRST(&handle->inqueue);
|
|
if (IP_NULL != nlmsg)
|
|
ipcom_list_remove(&nlmsg->next);
|
|
ipcom_netlink_nae_socket_unlock(handle->nae_sock);
|
|
|
|
if (IP_NULL != nlmsg)
|
|
{
|
|
int len = nlmsg->hdr->nlmsg_len;
|
|
|
|
ipcom_memcpy(&handle->rx[0], nlmsg->hdr, len);
|
|
ipnet_ip_free_reply(nlmsg);
|
|
return *cfg->stdio_die? -IP_ERRNO_ECONNABORTED : len;
|
|
}
|
|
|
|
if (*cfg->stdio_die)
|
|
return -IP_ERRNO_ECONNABORTED;
|
|
}
|
|
|
|
#else
|
|
struct Ip_sockaddr_nl nladdr;
|
|
struct Ip_iovec vec;
|
|
struct Ip_msghdr msg;
|
|
|
|
ipcom_memset(&nladdr, 0, sizeof(nladdr));
|
|
nladdr.nl_family = IP_AF_NETLINK;
|
|
IPCOM_SA_LEN_SET(&nladdr, sizeof(nladdr));
|
|
|
|
ipcom_memset(&msg, 0, sizeof(msg));
|
|
msg.msg_name = &nladdr;
|
|
msg.msg_namelen = sizeof(nladdr);
|
|
msg.msg_iov = &vec;
|
|
msg.msg_iovlen = 1;
|
|
|
|
vec.iov_base = handle->rx;
|
|
vec.iov_len = IPNET_IP_HANDLE_BUFFER;
|
|
|
|
if (*cfg->stdio_die)
|
|
return -IP_ERRNO_ECONNABORTED;
|
|
|
|
return ipcom_recvmsg(handle->fd, &msg, 0);
|
|
#endif
|
|
}
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_ip_dump_netlink(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_t *handle, Ip_u16 type, Ip_u8 family, int core, Ip_bool clear_replies)
|
|
{
|
|
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&handle->tx[0];
|
|
struct Ip_rtgenmsg *rth;
|
|
Ip_ssize_t ret;
|
|
|
|
ipcom_memset(nlh, 0, sizeof(*nlh));
|
|
nlh->nlmsg_flags = IP_NLM_F_ROOT|IP_NLM_F_MATCH|IP_NLM_F_REQUEST;
|
|
nlh->nlmsg_len = IP_NLMSG_LENGTH(0);
|
|
nlh->nlmsg_seq = ++handle->seq;
|
|
nlh->nlmsg_type = type;
|
|
|
|
rth = (struct Ip_rtgenmsg *)((char *)nlh + nlh->nlmsg_len);
|
|
rth->rtgen_family = family;
|
|
nlh->nlmsg_len += (Ip_u32) sizeof(*rth);
|
|
|
|
/* Send the request */
|
|
if (0 > (ret = ipnet_ip_send_netlink(handle, IP_NULL, core)))
|
|
return ret;
|
|
|
|
if (0 > (ret = ipnet_ip_collect_netlink(cfg, handle, clear_replies)))
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_ip_collect_netlink(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_t *handle, Ip_bool clear_replies)
|
|
{
|
|
struct Ip_nlmsghdr *nlh;
|
|
|
|
if (clear_replies)
|
|
ipnet_ip_free_replies(&handle->replies);
|
|
|
|
for (;;)
|
|
{
|
|
Ip_ssize_t val;
|
|
|
|
if (0 > (val = ipnet_ip_recv_netlink(cfg, handle)))
|
|
return val;
|
|
|
|
nlh = (struct Ip_nlmsghdr *)&handle->rx[0];
|
|
while (IP_NLMSG_OK(nlh, (unsigned)val))
|
|
{
|
|
/* */
|
|
if (nlh->nlmsg_pid == handle->src.nl_pid &&
|
|
nlh->nlmsg_seq == handle->seq)
|
|
{
|
|
Ipnet_ip_handle_msg_t *nlmsg;
|
|
|
|
/* */
|
|
if (nlh->nlmsg_type == IP_NLMSG_ERROR)
|
|
{
|
|
struct Ip_nlmsgerr *err = (struct Ip_nlmsgerr *)IP_NLMSG_DATA(nlh);
|
|
|
|
if (nlh->nlmsg_len < IP_NLMSG_LENGTH(sizeof(struct Ip_nlmsgerr)))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
return err->error;
|
|
}
|
|
|
|
/* Multipart message; we're done */
|
|
if (IP_NLMSG_DONE == nlh->nlmsg_type)
|
|
return 0;
|
|
|
|
|
|
/* Append this NLH */
|
|
nlmsg = ipnet_ip_alloc_reply(nlh->nlmsg_len);
|
|
if (IP_NULL == nlmsg)
|
|
return -IP_ERRNO_ENOMEM;
|
|
|
|
ipcom_list_insert_last(&handle->replies, &nlmsg->next);
|
|
ipcom_memcpy(nlmsg->hdr, nlh, nlh->nlmsg_len);
|
|
|
|
/* Do we need to find the end marker? */
|
|
if (IP_BIT_ISFALSE(nlh->nlmsg_flags, IP_NLM_F_MULTI))
|
|
return 0;
|
|
}
|
|
|
|
|
|
nlh = IP_NLMSG_NEXT(nlh, val);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_ip_request_netlink(Ipnet_ip_config_t *cfg, Ipnet_ip_handle_t *handle, struct Ip_nlmsghdr *nlh, int core, Ip_bool clear_replies)
|
|
{
|
|
Ip_ssize_t ret;
|
|
|
|
/* Specify buffer */
|
|
nlh = nlh? nlh : (struct Ip_nlmsghdr*) &handle->tx[0];
|
|
nlh->nlmsg_seq = ++handle->seq;
|
|
nlh->nlmsg_flags |= IP_NLM_F_REQUEST;
|
|
|
|
/* Send the request */
|
|
if (0 > (ret = ipnet_ip_send_netlink(handle, nlh, core)))
|
|
return ret;
|
|
else
|
|
{
|
|
Ip_ssize_t val;
|
|
|
|
if (IP_BIT_ISFALSE(nlh->nlmsg_flags, IP_NLM_F_ACK))
|
|
return ipnet_ip_collect_netlink(cfg, handle, clear_replies);
|
|
|
|
for (;;)
|
|
{
|
|
if (0 > (val = ipnet_ip_recv_netlink(cfg, handle)))
|
|
return val;
|
|
|
|
nlh = (struct Ip_nlmsghdr *)&handle->rx[0];
|
|
while (IP_NLMSG_OK(nlh, (unsigned)val))
|
|
{
|
|
/* */
|
|
if (nlh->nlmsg_pid == handle->src.nl_pid &&
|
|
nlh->nlmsg_seq == handle->seq)
|
|
{
|
|
/* */
|
|
if (nlh->nlmsg_type == IP_NLMSG_ERROR)
|
|
{
|
|
struct Ip_nlmsgerr *err = (struct Ip_nlmsgerr *)IP_NLMSG_DATA(nlh);
|
|
|
|
if (nlh->nlmsg_len < IP_NLMSG_LENGTH(sizeof(struct Ip_nlmsgerr)))
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
return err->error;
|
|
}
|
|
|
|
/* Multipart message; we're done */
|
|
if (IP_NLMSG_DONE == nlh->nlmsg_type)
|
|
return 0;
|
|
|
|
/* Do we need to find the end marker? */
|
|
if (IP_BIT_ISFALSE(nlh->nlmsg_flags, IP_NLM_F_MULTI))
|
|
return 0;
|
|
}
|
|
|
|
nlh = IP_NLMSG_NEXT(nlh, val);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_str_to_key(int *param, const Ipcom_cmd_int_str_map *map, const char *str)
|
|
{
|
|
int i;
|
|
|
|
if (str)
|
|
{
|
|
for (i = 0; map[i].str != IP_NULL; i++)
|
|
if (ipcom_strcmp(str, map[i].str) == 0)
|
|
{
|
|
*param = map[i].key;
|
|
return IP_TRUE;
|
|
}
|
|
}
|
|
return IP_FALSE;
|
|
}
|
|
|
|
IP_GLOBAL const char *
|
|
ipnet_ip_key_to_str(const Ipcom_cmd_int_str_map *map, int key, char *buf, Ip_size_t bufsize)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; map[i].str != IP_NULL; i++)
|
|
if (key == map[i].key)
|
|
return map[i].str;
|
|
|
|
if (buf)
|
|
{
|
|
ipcom_snprintf(buf, bufsize, "%d", key);
|
|
return buf;
|
|
}
|
|
|
|
return "<none>";
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipnet_ip_host_size(int family)
|
|
{
|
|
return family == IP_AF_INET? 32 : 128;
|
|
}
|
|
|
|
IP_GLOBAL const char *
|
|
ipnet_ip_format_host(int family, void *addr, int plen, char *buf, Ip_size_t bufsize, const char *defname)
|
|
{
|
|
union Ip_in_addr_union any;
|
|
|
|
if (addr == IP_NULL)
|
|
{
|
|
if (plen == 0 && IP_NULL != defname)
|
|
return defname;
|
|
|
|
ipcom_memset(&any, 0, sizeof(any));
|
|
addr = &any;
|
|
}
|
|
|
|
if (IP_NULL == ipcom_inet_ntop(family, addr, buf, bufsize))
|
|
return "<unknown>";
|
|
|
|
if (plen != -1 && plen != ipnet_ip_host_size(family))
|
|
ipcom_snprintf(buf + ipcom_strlen(buf), bufsize - ipcom_strlen(buf), "/%d", plen);
|
|
|
|
return buf;
|
|
}
|
|
|
|
IP_GLOBAL const char *
|
|
ipnet_ip_format_address(int family, void *addr, Ip_size_t alen, char *buf, Ip_size_t bufsize)
|
|
{
|
|
|
|
if ((IP_AF_INET == family && 4 == alen) || (IP_AF_INET6 == family && 16 == alen))
|
|
{
|
|
if (IP_NULL == ipcom_inet_ntop(family, addr, buf, bufsize))
|
|
return "<unknown>";
|
|
}
|
|
else
|
|
{
|
|
Ip_size_t i, sz;
|
|
unsigned char *uaddr = addr;
|
|
|
|
for (sz = 0, i = 0; i < alen; i++)
|
|
sz += (Ip_size_t) ipcom_snprintf(&buf[sz], bufsize - sz, "%s%02x", sz? ":" : "", uaddr[i]);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_create_mask(union Ip_in_addr_union *addr, Ip_size_t netbits)
|
|
{
|
|
Ip_size_t i;
|
|
|
|
ipcom_memset(addr, 0, sizeof(*addr));
|
|
for (i = 0; i < netbits; i++)
|
|
IP_BIT_SET(((Ip_u16*) addr)[i / 16], ip_htons(0x8000 >> (i % 16)));
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_apply_mask(void *net, Ip_size_t len, Ip_size_t bitcount)
|
|
{
|
|
Ip_size_t i;
|
|
Ip_u16 bit_n;
|
|
Ip_u16 *net16;
|
|
Ip_u16 *mask16;
|
|
union Ip_in_addr_union mask;
|
|
|
|
ipnet_ip_create_mask(&mask, len);
|
|
|
|
net16 = (Ip_u16*) net;
|
|
mask16 = (Ip_u16*) &mask;
|
|
for (i = 0; i < bitcount; i++)
|
|
{
|
|
bit_n = (Ip_u16) ip_htons(0x8000 >> (i % 16));
|
|
if (IP_BIT_ISFALSE(mask16[i >> 4], bit_n))
|
|
IP_BIT_CLR(net16[i >> 4], bit_n);
|
|
}
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_match_prefix(Ipnet_ip_prefix_t *prefix, void *addr)
|
|
{
|
|
union Ip_in_addr_union laddr;
|
|
|
|
ipcom_memcpy(&laddr, addr, prefix->prefix_max/8);
|
|
ipnet_ip_apply_mask(&laddr, prefix->prefix_length, prefix->prefix_max);
|
|
|
|
return 0 == ipcom_memcmp(&laddr, &prefix->prefix, prefix->prefix_max/8);
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_cmd_arg_pop(Ipnet_ip_config_t *cfg)
|
|
{
|
|
/* More arguments available? */
|
|
return ++cfg->pos < cfg->argc;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_cmd_arg_push(Ipnet_ip_config_t *cfg)
|
|
{
|
|
/* More arguments available? */
|
|
--cfg->pos;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_cmd_param_int(int *param, Ipnet_ip_config_t *cfg, const Ipcom_cmd_int_str_map *map)
|
|
{
|
|
char *eptr = IP_NULL;
|
|
|
|
/**/
|
|
if (IP_TRUE != ipnet_ip_cmd_arg_pop(cfg))
|
|
return IP_FALSE;
|
|
|
|
if (map)
|
|
{
|
|
if (ipnet_ip_str_to_key(param, map, cfg->argv[cfg->pos]))
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/* Resolve */
|
|
*param = (int)ipcom_strtol(cfg->argv[cfg->pos], &eptr, 0);
|
|
|
|
if ('\0' != *eptr)
|
|
return IP_FALSE;
|
|
|
|
/**/
|
|
return IP_TRUE;
|
|
}
|
|
|
|
/* STOLE IT FROM strtoul.c in vxworks */
|
|
IP_STATIC Ip_u64
|
|
ipnet_ip_strtoull(const char *nptr, char ** endptr, int base)
|
|
{
|
|
const char *s = nptr;
|
|
Ip_u64 acc;
|
|
int c;
|
|
Ip_u64 cutoff;
|
|
int neg = 0;
|
|
int any;
|
|
int cutlim;
|
|
|
|
/*
|
|
* See strtol for comments as to the logic used.
|
|
*/
|
|
do
|
|
{
|
|
c = *s++;
|
|
} while (ipcom_isspace (c));
|
|
|
|
if (c == '-')
|
|
{
|
|
neg = 1;
|
|
c = *s++;
|
|
}
|
|
else if (c == '+')
|
|
c = *s++;
|
|
|
|
if (((base == 0) || (base == 16)) &&
|
|
(c == '0') &&
|
|
((*s == 'x') || (*s == 'X')))
|
|
{
|
|
c = s[1];
|
|
s += 2;
|
|
base = 16;
|
|
}
|
|
|
|
if (base == 0)
|
|
base = (c == '0' ? 8 : 10);
|
|
|
|
cutoff = ((Ip_u64)(-1)) / (Ip_u64)base;
|
|
cutlim = (int) (((Ip_u64)(-1)) % (Ip_u64)base);
|
|
|
|
for (acc = 0, any = 0;; c = *s++)
|
|
{
|
|
if (isdigit (c))
|
|
c -= '0';
|
|
else if (isalpha (c))
|
|
c -= (isupper (c) ? 'A' - 10 : 'a' - 10);
|
|
else
|
|
break;
|
|
|
|
if (c >= base)
|
|
break;
|
|
|
|
if ((any < 0) || (acc > cutoff) || ((acc == cutoff) && (c > cutlim)))
|
|
any = -1;
|
|
else
|
|
{
|
|
any = 1;
|
|
acc *= (unsigned) base;
|
|
acc += (unsigned) c;
|
|
}
|
|
}
|
|
|
|
if (any < 0)
|
|
acc = (Ip_u64)-1;
|
|
else if (neg)
|
|
acc = -acc;
|
|
|
|
if (endptr != 0)
|
|
*endptr = (any ? (char *) (s - 1) : (char *) (nptr));
|
|
|
|
return (acc);
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_str_to_uint64(Ip_u64 *param, const char *str)
|
|
{
|
|
char *eptr = IP_NULL;
|
|
|
|
/* Resolve */
|
|
*param = (Ip_u64)ipnet_ip_strtoull(str, &eptr, 0);
|
|
if ('\0' != *eptr)
|
|
return IP_FALSE;
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_str_to_uint(Ip_u32 *param, const char *str, const Ipcom_cmd_int_str_map *map)
|
|
{
|
|
char *eptr = IP_NULL;
|
|
|
|
if (map)
|
|
{
|
|
int iparam;
|
|
if (ipnet_ip_str_to_key(&iparam, map, str))
|
|
{
|
|
*param = (Ip_u32)iparam;
|
|
return IP_TRUE;
|
|
}
|
|
}
|
|
|
|
/* Resolve */
|
|
*param = (Ip_u32)ipcom_strtoul(str, &eptr, 0);
|
|
|
|
if ('\0' != *eptr)
|
|
return IP_FALSE;
|
|
|
|
return IP_TRUE;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_str_to_ushort(Ip_u16 *param, const char *str, const Ipcom_cmd_int_str_map *map)
|
|
{
|
|
Ip_u32 uarg;
|
|
|
|
if (ipnet_ip_str_to_uint(&uarg, str, map))
|
|
{
|
|
*param = (Ip_u16)uarg;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_cmd_param_uint64(Ip_u64 *param, Ipnet_ip_config_t *cfg)
|
|
{
|
|
/**/
|
|
if (IP_TRUE != ipnet_ip_cmd_arg_pop(cfg))
|
|
return IP_FALSE;
|
|
|
|
return ipnet_ip_str_to_uint64(param, cfg->argv[cfg->pos]);
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_cmd_param_uint(Ip_u32 *param, Ipnet_ip_config_t *cfg, const Ipcom_cmd_int_str_map *map)
|
|
{
|
|
/**/
|
|
if (IP_TRUE != ipnet_ip_cmd_arg_pop(cfg))
|
|
return IP_FALSE;
|
|
|
|
return ipnet_ip_str_to_uint(param, cfg->argv[cfg->pos], map);
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_cmd_param_ushort(Ip_u16 *param, Ipnet_ip_config_t *cfg, const Ipcom_cmd_int_str_map *map)
|
|
{
|
|
Ip_u32 uarg;
|
|
|
|
if (ipnet_ip_cmd_param_uint(&uarg, cfg, map))
|
|
{
|
|
*param = (Ip_u16)uarg;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_cmd_param_str(char **param, Ipnet_ip_config_t *cfg)
|
|
{
|
|
/**/
|
|
if (IP_TRUE != ipnet_ip_cmd_arg_pop(cfg))
|
|
return IP_FALSE;
|
|
|
|
/* Resolve */
|
|
*param = cfg->argv[cfg->pos];
|
|
/**/
|
|
return IP_TRUE;
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipnet_cmd_ip_requires_argument(Ipnet_ip_config_t *cfg, const char *param)
|
|
{
|
|
ipnet_ip_stdio_printf(cfg, "%s requires an argument"IP_LF, param);
|
|
return -1;
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipnet_cmd_ip_unknown_keyword(Ipnet_ip_config_t *cfg, const char *param)
|
|
{
|
|
ipnet_ip_stdio_printf(cfg, "Unknown keyword \"%s\""IP_LF, param);
|
|
return -1;
|
|
}
|
|
|
|
IP_STATIC Ip_bool
|
|
ipnet_ip_str_to_addrdata(int family, const char *straddr, Ipnet_ip_prefix_t *prefix, Ip_bool mask)
|
|
{
|
|
char *str_prefix;
|
|
char *str_len;
|
|
Ip_bool success = IP_FALSE;
|
|
|
|
if (family == IP_AF_UNSPEC)
|
|
{
|
|
if (ipcom_strcasecmp(straddr, "default") == 0
|
|
|| ipcom_strcasecmp(straddr, "any") == 0
|
|
|| ipcom_strcasecmp(straddr, "all") == 0)
|
|
family = IP_AF_INET;
|
|
else if (IP_NULL == ipcom_strchr(straddr, ':'))
|
|
family = IP_AF_INET;
|
|
else
|
|
family = IP_AF_INET6;
|
|
}
|
|
|
|
if (family == IP_AF_INET)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
prefix->prefix_family = IP_AF_INET;
|
|
prefix->prefix_max = 32;
|
|
#else
|
|
return IP_FALSE;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef IPCOM_USE_INET6
|
|
prefix->prefix_family = IP_AF_INET6;
|
|
prefix->prefix_max = 128;
|
|
#else
|
|
return IP_FALSE;
|
|
#endif
|
|
}
|
|
|
|
if (ipcom_strcasecmp(straddr, "default") == 0
|
|
|| ipcom_strcasecmp(straddr, "any") == 0
|
|
|| ipcom_strcasecmp(straddr, "all") == 0)
|
|
{
|
|
ipcom_memset(&prefix->prefix, 0, sizeof(prefix->prefix));
|
|
prefix->prefix_length = 0;
|
|
return IP_TRUE;
|
|
}
|
|
|
|
str_len = str_prefix = ipcom_strdup(straddr);
|
|
if (IP_NULL == str_prefix)
|
|
goto cleanup;
|
|
|
|
while (*str_len != '/')
|
|
{
|
|
if (*str_len == '\0')
|
|
{
|
|
str_len = IP_NULL;
|
|
break;
|
|
}
|
|
str_len++;
|
|
}
|
|
|
|
if (IP_NULL != str_len)
|
|
*str_len++ = '\0';
|
|
|
|
if (ipcom_inet_pton((int) prefix->prefix_family, str_prefix, &prefix->prefix) != 1)
|
|
goto cleanup;
|
|
|
|
if (IP_NULL != str_len)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
if (prefix->prefix_family == IP_AF_INET)
|
|
{
|
|
/* Is this a 255.255.255.0 type of mask? */
|
|
if (IP_NULL != ipcom_strchr(str_len, '.'))
|
|
{
|
|
struct Ip_in_addr inet;
|
|
|
|
if (ipcom_inet_pton(IP_AF_INET, str_len, &inet) != 1)
|
|
goto cleanup;
|
|
|
|
prefix->prefix_length = (unsigned) ipcom_mask_to_prefixlen(&inet, 32);
|
|
}
|
|
else
|
|
{
|
|
prefix->prefix_length = ipcom_strtoul(str_len, IP_NULL, 0);
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
if (prefix->prefix_family == IP_AF_INET6)
|
|
{
|
|
prefix->prefix_length = ipcom_strtoul(str_len, IP_NULL, 0);
|
|
}
|
|
#endif
|
|
|
|
if (prefix->prefix_length > prefix->prefix_max)
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
prefix->prefix_length = prefix->prefix_max;
|
|
}
|
|
|
|
/* APPLY MASK - GET RID OF BITS */
|
|
if (IP_FALSE != mask)
|
|
ipnet_ip_apply_mask(&prefix->prefix, prefix->prefix_length, prefix->prefix_max);
|
|
|
|
success = IP_TRUE;
|
|
|
|
cleanup:
|
|
ipcom_free(str_prefix);
|
|
return success;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_str_to_prefix(int family, const char *straddr, Ipnet_ip_prefix_t *prefix)
|
|
{
|
|
return ipnet_ip_str_to_addrdata(family, straddr, prefix, IP_TRUE);
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_str_to_address(int family, const char *straddr, Ipnet_ip_prefix_t *prefix)
|
|
{
|
|
return ipnet_ip_str_to_addrdata(family, straddr, prefix, IP_FALSE);
|
|
}
|
|
|
|
IP_GLOBAL Ip_size_t
|
|
ipnet_ip_str_to_link_address(const char *strptr, unsigned char *address)
|
|
{
|
|
unsigned a_idx = 0;;
|
|
const char *sptr = strptr;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
if (1 == ipcom_inet_pton(IP_AF_INET, strptr, address))
|
|
return 4;
|
|
#endif
|
|
#if 0
|
|
#ifdef IPCOM_USE_INET6
|
|
if (1 == ipcom_inet_pton(IP_AF_INET6, strptr, address))
|
|
return 16;
|
|
#endif
|
|
#endif
|
|
|
|
for (;;)
|
|
{
|
|
char *endptr;
|
|
unsigned long value = ipcom_strtoul(sptr, &endptr, 16);
|
|
|
|
if (endptr == sptr || value > 0xFF)
|
|
return 0;
|
|
|
|
address[a_idx++] = (unsigned char)value;
|
|
|
|
if (*endptr == '\0')
|
|
return a_idx;
|
|
|
|
if (*endptr != ':')
|
|
return 0;
|
|
|
|
sptr = endptr + 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_ip_cmd_param_prefix(int family, Ipnet_ip_prefix_t *prefix, Ipnet_ip_config_t *cfg)
|
|
{
|
|
if (IP_TRUE != ipnet_ip_cmd_arg_pop(cfg))
|
|
return IP_FALSE;
|
|
|
|
/* Convert */
|
|
return ipnet_ip_str_to_prefix(family, cfg->argv[cfg->pos], prefix);
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipnet_cmd_ip_check_mask(Ipnet_ip_config_t *cfg, const char *param, int bit)
|
|
{
|
|
if (IP_NULL != param && IP_BIT_ISSET(cfg->mask, IP_BIT_UVAL64(bit)))
|
|
{
|
|
ipnet_ip_stdio_printf(cfg, "Duplicate parameter \'%s\'"IP_LF, param);
|
|
return IP_FALSE;
|
|
}
|
|
|
|
IP_BIT_SET(cfg->mask, IP_BIT_UVAL64(bit));
|
|
return IP_TRUE;
|
|
}
|
|
|
|
IP_GLOBAL Ip_u64
|
|
ipnet_cmd_ip_clear_mask(Ipnet_ip_config_t *cfg)
|
|
{
|
|
Ip_u64 old_mask = cfg->mask;
|
|
/**/
|
|
cfg->mask = 0;
|
|
|
|
return old_mask;
|
|
}
|
|
|
|
IP_GLOBAL Ip_u64
|
|
ipnet_cmd_ip_set_mask(Ipnet_ip_config_t *cfg, Ip_u64 mask)
|
|
{
|
|
Ip_u64 old_mask = cfg->mask;
|
|
/**/
|
|
cfg->mask = mask;
|
|
|
|
return old_mask;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_stdio_printf(Ipnet_ip_config_t *cfg, const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
ipcom_vsnprintf(cfg->stdio_buf, IPNET_IP_STDIO_BUFFER, format, ap);
|
|
|
|
if (IP_NULL != cfg->stdio_printf)
|
|
{
|
|
/* Send to output function */
|
|
(*cfg->stdio_printf) (cfg->stdio_cookie, cfg->stdio_buf);
|
|
}
|
|
else
|
|
{
|
|
/* Print */
|
|
ipcom_printf(cfg->stdio_buf);
|
|
}
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipnet_ip_stdio_flush(Ipnet_ip_config_t *cfg)
|
|
{
|
|
if (IP_NULL != cfg->stdio_flush)
|
|
(*cfg->stdio_flush) (cfg->stdio_cookie);
|
|
}
|
|
|
|
IP_GLOBAL const char *
|
|
ipnet_ip_if_indextoname(char *buf, Ip_u32 ifindex, int vr)
|
|
{
|
|
#ifndef IPCOM_FORWARDER_NAE
|
|
int vr_old = ipcom_proc_vr_get();
|
|
const char *ifname;
|
|
|
|
if (vr_old != vr)
|
|
ipcom_proc_vr_set(vr);
|
|
|
|
if (IP_NULL == (ifname = ipcom_if_indextoname(ifindex, buf)))
|
|
{
|
|
vr = IPCOM_VR_ANY;
|
|
ipcom_proc_vr_set(vr);
|
|
ifname = ipcom_if_indextoname(ifindex, buf);
|
|
}
|
|
|
|
if (vr_old != vr)
|
|
ipcom_proc_vr_set(vr_old);
|
|
return ifname;
|
|
#else
|
|
Ipnet_netif *netif = IP_NULL;
|
|
|
|
netif = ipnet_if_indextonetif(vr, ifindex);
|
|
if (IP_NULL == netif)
|
|
{
|
|
netif = ipnet_if_indextonetif(IPCOM_VR_ANY, ifindex);
|
|
if (IP_NULL == netif)
|
|
return "<unknown>";
|
|
}
|
|
|
|
ipcom_memcpy(buf, netif->ipcom.name, IP_IFNAMSIZ);
|
|
if (netif->vr_index != vr)
|
|
ipcom_sprintf(buf, "%s#%u", netif->ipcom.name, netif->vr_index);
|
|
else
|
|
ipcom_memcpy(buf, netif->ipcom.name, IP_IFNAMSIZ);
|
|
|
|
return buf;
|
|
#endif
|
|
}
|
|
|
|
IP_GLOBAL Ip_u32
|
|
ipnet_ip_if_nametoindex(const char *name, int vr)
|
|
{
|
|
#ifndef IPCOM_FORWARDER_NAE
|
|
int vr_old = ipcom_proc_vr_get();
|
|
Ip_u32 ifindex;
|
|
|
|
if (vr_old != vr)
|
|
ipcom_proc_vr_set(vr);
|
|
|
|
if (0 == (ifindex = ipcom_if_nametoindex(name)))
|
|
{
|
|
vr = IPCOM_VR_ANY;
|
|
ipcom_proc_vr_set(vr);
|
|
ifindex = ipcom_if_nametoindex(name);
|
|
}
|
|
|
|
if (vr_old != vr)
|
|
ipcom_proc_vr_set(vr_old);
|
|
return ifindex;
|
|
#else
|
|
Ipnet_netif *netif = IP_NULL;
|
|
|
|
netif = ipnet_if_nametonetif(vr, name);
|
|
if (IP_NULL == netif)
|
|
{
|
|
netif = ipnet_if_nametonetif(IPCOM_VR_ANY, name);
|
|
if (IP_NULL == netif)
|
|
return 0;
|
|
}
|
|
|
|
return netif->ipcom.ifindex;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* IP TOOL MONITOR MODULE
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_cmd_ip_module_flush(Ipnet_ip_config_t *cfg, Ip_u32 modules)
|
|
{
|
|
cfg->handle = ipnet_ip_open_netlink(cfg, 0, IP_NETLINK_ROUTE);
|
|
|
|
if (IP_UNLIKELY(cfg->handle == IP_NULL))
|
|
return 0;
|
|
|
|
if (IP_BIT_ISSET(modules, IP_BIT_UVAL(IPNET_IP_MODULE_ADDRESS)))
|
|
(void)ipnet_cmd_ip_module_address_flush_all(cfg);
|
|
|
|
if (IP_BIT_ISSET(modules, IP_BIT_UVAL(IPNET_IP_MODULE_ROUTE)))
|
|
(void)ipnet_cmd_ip_module_route_flush_all(cfg);
|
|
|
|
if (IP_BIT_ISSET(modules, IP_BIT_UVAL(IPNET_IP_MODULE_RULE)))
|
|
(void)ipnet_cmd_ip_module_rule_flush_all(cfg);
|
|
|
|
if (IP_BIT_ISSET(modules, IP_BIT_UVAL(IPNET_IP_MODULE_NEIGH)))
|
|
(void)ipnet_cmd_ip_module_neigh_flush_all(cfg);
|
|
|
|
if (IP_BIT_ISSET(modules, IP_BIT_UVAL(IPNET_IP_MODULE_LINK)))
|
|
(void)ipnet_cmd_ip_module_link_flush_all(cfg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef IPCOM_FORWARDER_NAE
|
|
IP_GLOBAL void ipnet_cmd_ip_module_nae_flush(void);
|
|
IP_GLOBAL void
|
|
ipnet_cmd_ip_module_nae_flush(void)
|
|
{
|
|
Ipnet_ip_config_t cfg;
|
|
Ip_u32 die = 0;
|
|
|
|
ipnet_cmd_ip_internal_init(&cfg, 0, IP_NULL);
|
|
|
|
cfg.is_silent = IP_TRUE;
|
|
cfg.stdio_die = ¨
|
|
|
|
ipnet_cmd_ip_module_flush(&cfg,
|
|
IP_BIT_UVAL(IPNET_IP_MODULE_ADDRESS) |
|
|
IP_BIT_UVAL(IPNET_IP_MODULE_ROUTE) |
|
|
IP_BIT_UVAL(IPNET_IP_MODULE_RULE) |
|
|
IP_BIT_UVAL(IPNET_IP_MODULE_NEIGH) |
|
|
IP_BIT_UVAL(IPNET_IP_MODULE_LINK));
|
|
|
|
ipnet_ip_close_netlink(cfg.handle);
|
|
}
|
|
#endif
|
|
/*
|
|
****************************************************************************
|
|
* IP TOOL MONITOR MODULE
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_cmd_ip_module_monitor(Ipnet_ip_config_t *cfg, Ip_u32 modules)
|
|
{
|
|
unsigned i;
|
|
Ip_u32 groups = 0;
|
|
Ip_ssize_t val;
|
|
|
|
for (i = 0; i < IPNET_IP_MODULE_MAX; i++)
|
|
{
|
|
if (IP_BIT_ISSET(modules, IP_BIT_UVAL(i)))
|
|
{
|
|
switch (i)
|
|
{
|
|
case IPNET_IP_MODULE_ROUTE:
|
|
groups |= ipnet_cmd_ip_module_route_monitor_groups(cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_NEIGH:
|
|
groups |= ipnet_cmd_ip_module_neigh_monitor_groups(cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_RULE:
|
|
groups |= ipnet_cmd_ip_module_rule_monitor_groups(cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_LINK:
|
|
groups |= ipnet_cmd_ip_module_link_monitor_groups(cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_VR:
|
|
groups |= ipnet_cmd_ip_module_vr_monitor_groups(cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_ADDRESS:
|
|
groups |= ipnet_cmd_ip_module_address_monitor_groups(cfg);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (groups == 0)
|
|
{
|
|
ipnet_ip_stdio_printf(cfg, "No groups selected"IP_LF);
|
|
return -1;
|
|
}
|
|
|
|
cfg->handle = ipnet_ip_open_netlink(cfg, groups, IP_NETLINK_ROUTE);
|
|
if (IP_NULL == cfg->handle)
|
|
return -1;
|
|
|
|
while (0 < (val = ipnet_ip_recv_netlink(cfg, cfg->handle)))
|
|
{
|
|
struct Ip_nlmsghdr *nlh = (struct Ip_nlmsghdr *)&cfg->handle->rx[0];
|
|
|
|
while (IP_NLMSG_OK(nlh, (unsigned)val))
|
|
{
|
|
Ipnet_ip_handle_msg_t *nlmsg = ipnet_ip_alloc_reply(nlh->nlmsg_len);
|
|
|
|
if (IP_NULL == nlmsg)
|
|
return -1;
|
|
|
|
ipcom_memcpy(nlmsg->hdr, nlh, nlh->nlmsg_len);
|
|
for (i = 0; i < IPNET_IP_MODULE_MAX; i++)
|
|
{
|
|
if (IP_BIT_ISSET(modules, IP_BIT_UVAL(i)))
|
|
{
|
|
switch (i)
|
|
{
|
|
case IPNET_IP_MODULE_ROUTE:
|
|
if (ipnet_cmd_ip_module_route_monitor(cfg, nlmsg))
|
|
goto next_frame;
|
|
break;
|
|
case IPNET_IP_MODULE_NEIGH:
|
|
if (ipnet_cmd_ip_module_neigh_monitor(cfg, nlmsg))
|
|
goto next_frame;
|
|
break;
|
|
case IPNET_IP_MODULE_RULE:
|
|
if (ipnet_cmd_ip_module_rule_monitor(cfg, nlmsg))
|
|
goto next_frame;
|
|
break;
|
|
case IPNET_IP_MODULE_LINK:
|
|
if (ipnet_cmd_ip_module_link_monitor(cfg, nlmsg))
|
|
goto next_frame;
|
|
break;
|
|
case IPNET_IP_MODULE_VR:
|
|
if (ipnet_cmd_ip_module_vr_monitor(cfg, nlmsg))
|
|
goto next_frame;
|
|
break;
|
|
case IPNET_IP_MODULE_ADDRESS:
|
|
if (ipnet_cmd_ip_module_address_monitor(cfg, nlmsg))
|
|
goto next_frame;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
next_frame:
|
|
nlh = IP_NLMSG_NEXT(nlh, val);
|
|
ipnet_ip_free_reply(nlmsg);
|
|
|
|
/* Flush output */
|
|
ipnet_ip_stdio_flush(cfg);
|
|
}
|
|
}
|
|
|
|
return val < 0? val : 0;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* IP TOOL MODULE
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
IP_GLOBAL Ip_ssize_t
|
|
ipnet_cmd_ip_exec(int argc, char **argv, Ipnet_ip_stdio_printf_t stdio_printf, Ipnet_ip_stdio_flush_t stdio_flush, void *stdio_cookie, Ip_u32 *stdio_die)
|
|
{
|
|
int arg, param;
|
|
char *sparam, *sarg;
|
|
Ip_ssize_t ret = 0;
|
|
Ipnet_ip_config_t cfg;
|
|
|
|
ipnet_cmd_ip_internal_init(&cfg, argc, argv);
|
|
|
|
cfg.stdio_printf = stdio_printf;
|
|
cfg.stdio_flush = stdio_flush;
|
|
cfg.stdio_cookie = stdio_cookie;
|
|
cfg.stdio_die = stdio_die;
|
|
|
|
while (IP_FALSE != ipnet_ip_cmd_param_str(&sarg, &cfg))
|
|
{
|
|
if (ipnet_ip_str_to_key(&arg, ipnet_ip_main, sarg))
|
|
{
|
|
switch (arg)
|
|
{
|
|
case IPNET_IP_MAIN_ARG_VR:
|
|
if (IP_TRUE != ipnet_cmd_ip_check_mask(&cfg, "-V <vr>", arg))
|
|
return -1;
|
|
|
|
if (IP_TRUE != ipnet_ip_cmd_param_int(¶m, &cfg, ipnet_ip_vr_values))
|
|
return ipnet_cmd_ip_requires_argument(&cfg, "-V <vr>");
|
|
#if IPCOM_VR_MAX > 1
|
|
cfg.vr = (Ip_u16)param;
|
|
#if !defined(IPCOM_FORWARDER_NAE)
|
|
if (cfg.vr != IPCOM_VR_ANY)
|
|
ipcom_proc_vr_set(cfg.vr);
|
|
#endif
|
|
#endif
|
|
break;
|
|
case IPNET_IP_MAIN_ARG_CORE:
|
|
if (IP_TRUE != ipnet_cmd_ip_check_mask(&cfg, "-c <core>", arg))
|
|
return -1;
|
|
|
|
if (IP_TRUE != ipnet_ip_cmd_param_int(¶m, &cfg, ipnet_ip_core_values))
|
|
return ipnet_cmd_ip_requires_argument(&cfg, "-c <core>");
|
|
|
|
cfg.core = param;
|
|
break;
|
|
|
|
case IPNET_IP_MAIN_ARG_FAMILY_X:
|
|
if (IP_TRUE != ipnet_ip_cmd_param_str(&sparam, &cfg))
|
|
return ipnet_cmd_ip_requires_argument(&cfg, "-family <link|inet|inet6>");
|
|
|
|
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_main_family, sparam))
|
|
{
|
|
ipnet_ip_stdio_printf(&cfg, "Unable to interpret family \"%s\""IP_LF, sparam);
|
|
return -1;
|
|
}
|
|
cfg.family = (Ip_u8) arg;
|
|
break;
|
|
case IPNET_IP_MAIN_ARG_FAMILY_PACKET:
|
|
cfg.family = IP_AF_PACKET;
|
|
break;
|
|
#ifdef IPCOM_USE_INET
|
|
case IPNET_IP_MAIN_ARG_FAMILY_INET:
|
|
cfg.family = IP_AF_INET;
|
|
break;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IPNET_IP_MAIN_ARG_FAMILY_INET6:
|
|
cfg.family = IP_AF_INET6;
|
|
break;
|
|
#endif
|
|
case IPNET_IP_MAIN_ARG_SHOW_DETAILS:
|
|
cfg.show_details = 1;
|
|
break;
|
|
case IPNET_IP_MAIN_ARG_SHOW_STATS:
|
|
cfg.show_stats = 1;
|
|
break;
|
|
case IPNET_IP_MAIN_ARG_SILENT:
|
|
cfg.is_silent = IP_TRUE;
|
|
break;
|
|
case IPNET_IP_MAIN_ARG_ONELINE:
|
|
cfg.oneline = "\\";
|
|
cfg.is_oneline = IP_TRUE;
|
|
break;
|
|
case IPNET_IP_MAIN_ARG_HELP:
|
|
return ipnet_cmd_ip_usage(&cfg, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Unmatched parameter - No longer global flags */
|
|
ipnet_ip_cmd_arg_push(&cfg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Resolve the module */
|
|
if (IP_TRUE != ipnet_ip_cmd_param_str(&sparam, &cfg))
|
|
return ipnet_cmd_ip_usage(&cfg, -1);
|
|
|
|
/* Resolve the module */
|
|
if (IP_FALSE == ipnet_ip_str_to_key(&arg, ipnet_ip_module, sparam))
|
|
return ipnet_cmd_ip_unknown_keyword(&cfg, sparam);
|
|
else
|
|
{
|
|
switch (arg)
|
|
{
|
|
case IPNET_IP_MODULE_ROUTE:
|
|
ret = ipnet_cmd_ip_module_route(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_TUNNEL:
|
|
ret = ipnet_cmd_ip_module_link(&cfg, "tunnel");
|
|
break;
|
|
case IPNET_IP_MODULE_LINK:
|
|
ret = ipnet_cmd_ip_module_link(&cfg, IP_NULL);
|
|
break;
|
|
case IPNET_IP_MODULE_NEIGH:
|
|
ret = ipnet_cmd_ip_module_neigh(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_VR:
|
|
ret = ipnet_cmd_ip_module_vr(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_ADDRESS:
|
|
ret = ipnet_cmd_ip_module_address(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_RULE:
|
|
ret = ipnet_cmd_ip_module_rule(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_XFRM:
|
|
ret = ipnet_cmd_ip_module_xfrm(&cfg);
|
|
break;
|
|
#ifdef IPCOM_FORWARDER_NAE
|
|
case IPNET_IP_MODULE_FWC:
|
|
ret = ipnet_cmd_ip_module_fwc(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_NAE:
|
|
ret = ipnet_cmd_ip_module_nae(&cfg);
|
|
break;
|
|
#endif
|
|
#ifdef IPCOM_USE_FORWARDER_IPSEC
|
|
case IPNET_IP_MODULE_SAC:
|
|
ret = ipnet_cmd_ip_module_sac(&cfg);
|
|
break;
|
|
#endif
|
|
case IPNET_IP_MODULE_MONITOR:
|
|
ret = ipnet_cmd_ip_module_monitor_internal(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_FLUSH:
|
|
ret = ipnet_cmd_ip_module_flush_internal(&cfg);
|
|
break;
|
|
case IPNET_IP_MODULE_HELP:
|
|
ret = ipnet_cmd_ip_usage(&cfg, 0);
|
|
break;
|
|
default:
|
|
ret = ipnet_cmd_ip_unknown_keyword(&cfg, sparam);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ipnet_ip_stdio_flush(&cfg);
|
|
ipnet_ip_close_netlink(cfg.handle);
|
|
return ret;
|
|
}
|
|
|
|
IP_PUBLIC int
|
|
ipnet_cmd_ip(int argc, char **argv)
|
|
{
|
|
#if !defined(IPCOM_FORWARDER_NAE)
|
|
#if IPCOM_VR_MAX > 1
|
|
Ip_u16 vr_index = (Ip_u16) ipcom_proc_vr_get();
|
|
#endif
|
|
#endif
|
|
Ip_u32 die = 0;
|
|
|
|
/* Invoke the 'real' command */
|
|
Ip_ssize_t ret = ipnet_cmd_ip_exec(argc, argv, IP_NULL, IP_NULL, IP_NULL, &die);
|
|
|
|
#if !defined(IPCOM_FORWARDER_NAE)
|
|
#if IPCOM_VR_MAX > 1
|
|
/* Restore the VR if required */
|
|
ipcom_proc_vr_set(vr_index);
|
|
#endif
|
|
#endif
|
|
|
|
/* Return the return value */
|
|
return (int) ret;
|
|
}
|
|
|
|
#else
|
|
IP_PUBLIC int
|
|
ipnet_cmd_ip(int argc, char **argv)
|
|
{
|
|
ipcom_printf("You need NETLINK support in order to use the ip command"IP_LF);
|
|
return 0;
|
|
}
|
|
#endif /* IPNET_USE_NETLINK */
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|