/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_cmd_ndp.c,v $ $Revision: 1.50.10.3 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_cmd_ndp.c,v $ * $Author: kenneth $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifdef IPCOM_KERNEL #undef IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPCOM_USE_INET6 #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_routesock.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_ndp_expire_time_str *=========================================================================== * Description: * Parameters: expires - IPCOM_ADDR_INFINITE, or time in seconds until * entry expiration * str_expire - buffer to write string representing 'expires' * into * Returns: str_expire * */ IP_STATIC IP_CONST char* ipnet_ndp_expire_time_str(Ip_u32 expires, char *str_expire) { if (expires == (Ip_time_t)IPCOM_ADDR_INFINITE) ipcom_sprintf(str_expire, "perm"); else ipcom_sprintf(str_expire, "%u s", expires); return str_expire; } /* *=========================================================================== * ipnet_ndp_state_str *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC char ipnet_ndp_state_str(Ipnet_nd_state_t status) { switch (status) { case IPNET_ND_REACHABLE: return 'R'; case IPNET_ND_STALE: return 'S'; case IPNET_ND_DELAY: return 'D'; case IPNET_ND_PROBE: return 'P'; default: /* Incomplete */ return 'I'; } } /* *=========================================================================== * ipnet_ndp_print_ndp_entry *=========================================================================== * Description: Prints a NDP entry * Parameters: rt - A NDP entry * addrs - Addresses for this NDP entry. * Returns: 0 = success, -1 = fail. * */ IP_STATIC int ipnet_ndp_print_entry(struct Ipnet_rt_msghdr *rt, struct Ip_sockaddr *addrs[IPNET_RTAX_MAX]) { struct Ipnet_tag_nc_entry tag; char str[256]; int ret; tag.hdr.type = IPNET_CTRL_GET_NC_ENTRY; tag.hdr.size = sizeof(tag); tag.ifindex = rt->rtm_index; ipcom_memcpy(&tag.addr, addrs[IPNET_RTAX_DST], sizeof(tag.addr)); tag.vr_index = (Ip_u16) ipcom_proc_vr_get(); ret = ipnet_ctrl(&tag.hdr); if (ret < 0) return ret; ipcom_printf("%-35s ", ipcom_cmd_sockaddr_to_str((struct Ip_sockaddr *) &tag.addr, IP_FALSE, IP_TRUE, str, sizeof(str))); ipcom_printf("%-18s ", ipcom_cmd_sockaddr_to_str((struct Ip_sockaddr *) &tag.link_addr, IP_FALSE, IP_TRUE, str, sizeof(str))); ipcom_printf("%-9s ", ipcom_if_indextoname(tag.ifindex, str)); ipcom_printf("%-7s ", ipnet_ndp_expire_time_str(tag.expires_sec, str)); ipcom_printf("%c", ipnet_ndp_state_str(tag.state)); ipcom_printf("\n"); return 0; } /* *=========================================================================== * ipnet_ndp_delete_ndp_entry *=========================================================================== * Description: Deletes a NDP entry. * Parameters: silent - IP_TRUE to quench any output to stdout. * ifindex - interface the NDP entry is assigned to * str_ip6_addr - the IPv6 address of the NDP entry * Returns: 0 = success, -1 == error * */ IP_STATIC int ipnet_ndp_delete_ndp_entry(Ip_bool silent, Ip_u32 ifindex, IP_CONST char *str_ip6_addr) { struct Ipnet_tag_nc_entry tag; if (ipcom_getsockaddrbyaddrname(IP_AF_INET6, IP_TRUE, str_ip6_addr, (struct Ip_sockaddr *) &tag.addr) < 0) { if (silent == IP_FALSE) ipcom_printf("%s is not a valid IPv6 address\n", str_ip6_addr); return -1; } tag.hdr.type = IPNET_CTRL_DEL_NC_ENTRY; tag.hdr.size = sizeof(tag); tag.vr_index = (Ip_u16) ipcom_proc_vr_get(); tag.ifindex = ifindex; if (ipnet_ctrl(&tag.hdr) < 0) { if (silent == IP_FALSE) ipcom_printf("Failed to delete %s: %s", str_ip6_addr, ipcom_strerror(ipcom_errno)); return -1; } return 0; } /* *=========================================================================== * ipnet_ndp_delete_cb *=========================================================================== * Description: Deletes a single NDP entry. * Parameters: rt - An NDP entry. * addrs - Addresses in the NDP entry. * Returns: 0 == success, <0 == error * */ IP_STATIC int ipnet_ndp_delete_cb(struct Ipnet_rt_msghdr *rt, struct Ip_sockaddr *addrs[IPNET_RTAX_MAX]) { char addr_str[IP_INET6_ADDRSTRLEN]; struct Ip_sockaddr_in6 *in6; in6 = (struct Ip_sockaddr_in6 *) addrs[IPNET_RTAX_DST]; return ipnet_ndp_delete_ndp_entry(IP_TRUE, rt->rtm_index, ipcom_inet_ntop(IP_AF_INET6, &in6->sin6_addr, addr_str, sizeof(addr_str))); } /* *=========================================================================== * ipnet_ndp_print_default_router_entries *=========================================================================== * Description: Prints all default routers. * Parameters: silent - IP_TRUE to suppress any output to stdout. * Returns: 0 = success, -1 = fail. * */ IP_STATIC int ipnet_ndp_print_prefix_entries(Ip_bool silent) { if (silent == IP_FALSE) { struct Ipnet_tag_prefix_entry tag; char str[44]; int ret; ipcom_printf("%-40s%-10s%-8s\n", "Prefix", "Expire", "Netif"); tag.hdr.type = IPNET_CTRL_NEW_ENUM_PREFIX_ENTRY; tag.hdr.size = sizeof(tag); tag.ifindex = 0; tag.vr_index = (Ip_u16) ipcom_proc_vr_get(); for (;;) { ret = ipnet_ctrl(&tag.hdr); if (ret == IPNET_CTRL_ENUM_DONE) break; if (ret < 0) { ipcom_printf("ipnet_ctrl() failed to enumerate prefix entry: %s"IP_LF, ipcom_strerror(ipcom_errno)); return -1; } tag.hdr.type = IPNET_CTRL_CONT_ENUM_PREFIX_ENTRY; (void)ipcom_cmd_sockaddr_to_str((struct Ip_sockaddr *) &tag.prefix, IP_FALSE, IP_FALSE, str, sizeof(str)); ipcom_sprintf(&str[ipcom_strlen(str)], "/%d", tag.bits); ipcom_printf("%-39s ", str); ipcom_printf("%-9s ", ipnet_ndp_expire_time_str(tag.expires_sec, str)); ipcom_printf("%-7s ", ipcom_if_indextoname(tag.ifindex, str)); ipcom_printf("\n"); } } return 0; } /* *=========================================================================== * ipnet_ndp_print_default_router_entries *=========================================================================== * Description: Prints all routers that has announced themself. * Parameters: silent - IP_TRUE to suppress any output to stdout. * Returns: 0 = success, -1 = fail. * */ IP_STATIC int ipnet_ndp_print_default_router_entries(Ip_bool silent) { if (silent == IP_FALSE) { struct Ipnet_tag_router_entry tag; char str[IP_INET6_ADDRSTRLEN]; int ret; ipcom_printf("%-36s%-10s%-8s\n", "Router address", "Expire", "Netif"); tag.hdr.type = IPNET_CTRL_NEW_ENUM_ROUTER_ENTRY; tag.hdr.size = sizeof(tag); tag.vr_index = (Ip_u16) ipcom_proc_vr_get(); for (;;) { ret = ipnet_ctrl(&tag.hdr); if (ret == IPNET_CTRL_ENUM_DONE) break; if (ret < 0) { ipcom_printf("ipnet_ctrl() failed to get router entry: %s"IP_LF, ipcom_strerror(ipcom_errno)); return -1; } tag.hdr.type = IPNET_CTRL_CONT_ENUM_ROUTER_ENTRY; ipcom_printf("%-35s ", ipcom_inet_ntop(IP_AF_INET6, &tag.addr, str, sizeof(str))); ipcom_printf("%-9s ", ipnet_ndp_expire_time_str(tag.expires_sec, str)); ipcom_printf("%-7s ", ipcom_if_indextoname(tag.ifindex, str)); ipcom_printf("\n"); } } return 0; } /* *=========================================================================== * ipnet_ndp_remove_all_default_router_entries *=========================================================================== * Description: Remove all default router entries. * Parameters: silent - IP_TRUE to suppress any output to stdout. * Returns: 0 = success, -1 = fail. * */ IP_STATIC int ipnet_ndp_remove_all_default_router_entries(Ip_bool silent) { struct Ipnet_tag_router_entry tag; int ret; tag.hdr.size = sizeof(tag); tag.vr_index = (Ip_u16) ipcom_proc_vr_get(); for (;;) { tag.hdr.type = IPNET_CTRL_NEW_ENUM_ROUTER_ENTRY; ret = ipnet_ctrl(&tag.hdr); if (ret == IPNET_CTRL_ENUM_DONE) break; if (ret < 0) { if (silent == IP_FALSE) ipcom_printf("ipnet_ctrl() failed to get router entry: %s"IP_LF, ipcom_strerror(ipcom_errno)); return -1; } tag.hdr.type = IPNET_CTRL_DEL_ROUTER_ENTRY; if (ipnet_ctrl(&tag.hdr) < 0) { if (silent == IP_FALSE) ipcom_printf("ipnet_ctrl() failed to delete router entry: %s"IP_LF, ipcom_strerror(ipcom_errno)); return -1; } } return 0; } /* *=========================================================================== * ipnet_ndp_add_entry *=========================================================================== * Description: Adds a neighbor cache entry. * Parameters: ifname - The name of the interface to a NC entry. * str_ip6_addr - The address of the entry. * str_link_addr - The link layer address. * Returns: 0 = success, -1 = fail. * */ IP_STATIC int ipnet_ndp_add_entry(Ip_bool silent, Ip_u32 ifindex, IP_CONST char *str_ip6_addr, IP_CONST char *str_link_addr) { struct Ipnet_tag_nc_entry tag; char ifname[IP_IFNAMSIZ]; if (ifindex) ipcom_if_indextoname(ifindex, ifname); else strncpy(ifname, "*unspecified*", IP_IFNAMSIZ); if (ipcom_getsockaddrbyaddrname(IP_AF_INET6, IP_TRUE, str_ip6_addr, (struct Ip_sockaddr *) &tag.addr) < 0) { if (silent == IP_FALSE) ipcom_printf("%s is not a valid IPv6 address\n", str_ip6_addr); goto errout; } tag.hdr.type = IPNET_CTRL_ADD_NC_ENTRY; tag.hdr.size = sizeof(tag); tag.ifindex = ifindex; tag.is_router = IP_FALSE; tag.expires_sec = IPCOM_ADDR_INFINITE; tag.vr_index = (Ip_u16) ipcom_proc_vr_get(); if (ipcom_getsockaddrbyaddr(IP_AF_LINK, str_link_addr, (struct Ip_sockaddr *) &tag.link_addr) < 0) { if (silent == IP_FALSE) ipcom_printf("%s is not a valid link address for %s\n", str_link_addr, (ipcom_if_indextoname(ifindex, ifname) ? ifname : "")); return -1; } if (ipnet_ctrl(&tag.hdr) < 0) { if (silent == IP_FALSE) ipcom_printf("Failed to add NC entry to %s\n", (ipcom_if_indextoname(ifindex, ifname) ? ifname : "")); goto errout; } return 0; errout: return -1; } /* *=========================================================================== * ipnet_ndp_print_usage *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipnet_ndp_print_usage(void) { ipcom_printf(IP_LF); ipcom_printf("NAME" IP_LF); ipcom_printf(" ndp - control/diagnose IPv6 neighbor discovery protocol" IP_LF); ipcom_printf(IP_LF); ipcom_printf("SYNOPSIS" IP_LF); ipcom_printf(" ndp [-silent] [-V ] -a" IP_LF); ipcom_printf(" ndp [-silent] [-V ] -A" IP_LF); ipcom_printf(" ndp [-silent] [-V ] -c" IP_LF); ipcom_printf(" ndp [-silent] [-V ] [-i ] -d hostaddress" IP_LF); ipcom_printf(" ndp [-silent] [-V ] -p" IP_LF); ipcom_printf(" ndp [-silent] [-V ] -r" IP_LF); ipcom_printf(" ndp [-silent] [-V ] -R" IP_LF); ipcom_printf(" ndp [-silent] [[-V ] | [-i ]] -s nodeaddress ether_addr" IP_LF); ipcom_printf(IP_LF); ipcom_printf("DESCRIPTION" IP_LF); ipcom_printf(" The ndp command manipulates the address mapping table used by Neighbor" IP_LF); ipcom_printf(" Discovery Protocol (NDP). It can take up to 1 minute before deleted" IP_LF); ipcom_printf(" entries is removed, but they should be shown as 'expired' immediately." IP_LF); ipcom_printf(IP_LF); ipcom_printf(" Options:"IP_LF); ipcom_printf(" -silent Suppress output. MUST be first argument"IP_LF); ipcom_printf(" -i Specify interface. Selected by the stack otherwise."IP_LF); ipcom_printf(" -V Specify route table. = 0 if not specified."IP_LF); ipcom_printf(IP_LF); ipcom_printf(" Commands:" IP_LF); ipcom_printf(" -a Dump the currently existing NDP entries." IP_LF); ipcom_printf(" -A Erase all NDP entries." IP_LF); ipcom_printf(" -d Delete specified NDP entry." IP_LF); ipcom_printf(" -p Show prefix list." IP_LF); ipcom_printf(" -r Show the list of default routers added by the router advertisement protocol." IP_LF); ipcom_printf(" -R Flush all default routers added by the router advertisement protocol." IP_LF); ipcom_printf(" -s Register a NDP entry for a node. The entry will be permanent." IP_LF); ipcom_printf(" Specify -V or -i, not both." IP_LF); ipcom_printf("" IP_LF); } /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_cmd_ndp *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC int ipnet_cmd_ndp(int argc, char **argv) { #if IPCOM_VR_MAX > 1 Ip_u16 org_vr_index = (Ip_u16) ipcom_proc_vr_get(); Ip_u16 vr_index = org_vr_index; #endif Ip_u32 ifindex = 0; Ip_bool silent = IP_FALSE; int c; int ret = 17; Ipcom_getopt opt; if (argc > 1) { if (ipcom_strcmp(argv[1], "-silent") == 0) { silent = IP_TRUE; argc--; argv++; } } /* Parse options */ ipcom_getopt_clear_r(&opt); while ((c = ipcom_getopt_r(argc, argv, "AHPRad:hprsV:i:", &opt)) != -1) { switch (c) { case 'V' : #if IPCOM_VR_MAX > 1 vr_index = (Ip_u16) ipcom_atoi(opt.optarg); #endif break; case 'i' : ifindex = ipcom_if_nametoindex(opt.optarg); if(ifindex == 0) { if (silent == IP_FALSE) ipcom_printf("%s is not a valid interface."IP_LF, opt.optarg); goto done; } break; default: break; } } #if IPCOM_VR_MAX > 1 ipcom_proc_vr_set(vr_index); #endif ipcom_getopt_clear_r(&opt); while ((c = ipcom_getopt_r(argc, argv, "AHRad:hprsV:i:", &opt)) != -1) { switch (c) { case 'a': ipcom_printf("%-35s %-18s %-9s %-7s %-4s\n", "Neighbor", "Linklayer Address", "Netif", "Expire", "St"); ret = ipnet_cmd_neigh_for_each(IP_AF_INET6, ifindex, IP_TRUE, ipnet_ndp_print_entry); break; case 'A': ret = ipnet_cmd_neigh_for_each(IP_AF_INET6, ifindex, IP_TRUE, ipnet_ndp_delete_cb); break; case 'd': ret = ipnet_ndp_delete_ndp_entry(silent, ifindex, opt.optarg); break; case 'p': ret = ipnet_ndp_print_prefix_entries(silent); break; case 'R': ret = ipnet_ndp_remove_all_default_router_entries(silent); break; case 'r': ret = ipnet_ndp_print_default_router_entries(silent); break; case 's': if (argc < opt.optind + 2) goto done; ret = ipnet_ndp_add_entry(silent, ifindex, argv[opt.optind], argv[opt.optind+1]); break; default: break; } } done: #if IPCOM_VR_MAX > 1 ipcom_proc_vr_set(org_vr_index); #endif if (ret == 17 && silent == IP_FALSE) ipnet_ndp_print_usage(); return ret; } #endif /* IPCOM_USE_INET6 */ /* **************************************************************************** * END OF FILE **************************************************************************** */