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

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 = &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(&param, &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(&param, &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
****************************************************************************
*/