/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifdef IPCOM_KERNEL #undef IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #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 ] [-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 Switch to Virtual Router "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 ""; } 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 ""; 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 ""; } 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 ""; } 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 ", 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 "); #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 ", 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 "); 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 "); 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 **************************************************************************** */