/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: iplite_cmd_ndp.c,v $ $Revision: 1.22 $ * $Source: /home/interpeak/CVSRoot/iplite2/src/iplite_cmd_ndp.c,v $ * $Author: kenneth $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "iplite_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPCOM_USE_INET6 #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include "iplite.h" #include "iplite_h.h" #include "iplite_ip6.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_PUBLIC int iplite_cmd_ndp(int argc, char **argv); /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iplite_ndp_expire_time_str *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC IP_CONST char* iplite_ndp_expire_time_str(Ip_time_t expires, char *str_expire) { if (expires == (Ip_time_t)IPCOM_ADDR_INFINITE) ipcom_sprintf(str_expire, "permanent"); else if (expires == IPLITE_EXPIRED) ipcom_sprintf(str_expire, "expired"); else ipcom_sprintf(str_expire, "%ld s", (long)(expires - iplite.seconds)); return str_expire; } /* *=========================================================================== * iplite_ndp_status_str *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC char iplite_ndp_status_str(Ip_u16 status) { switch (status) { case IPLITE_IP6_ND_INCOMPLETE: return 'I'; case IPLITE_IP6_ND_REACHABLE: return 'R'; case IPLITE_IP6_ND_STALE: return 'S'; case IPLITE_IP6_ND_DELAY: return 'D'; case IPLITE_IP6_ND_PROBE: return 'P'; default: return ' '; } } /* *=========================================================================== * iplite_ndp_print_neighbor_cache_entries *=========================================================================== * Description: Prints all neighbor cache entries. * Parameters: * Returns: 0 = success, -1 = fail. * */ IP_STATIC int iplite_ndp_print_neighbor_cache_entries(void) { Iplite_ip6_nc_entry *nc; char str[256]; struct Ip_sockaddr_in6 addr; Iplite_netif *netif; int i; ipcom_printf("%-36s%-20s%-6s%-10s%-4s\n", "Neighbor", "Linklayer Address", "Netif", "Expire", "St"); addr.sin6_len = sizeof (struct Ip_sockaddr_in6); addr.sin6_family = IP_AF_INET6; for (i = 2; i < IPLITE_CONF_MAX_NETIF; i++) { IPLITE_CODE_LOCK(); netif = iplite.netifs[i]; if (netif == IP_NULL) goto skip; /* Lock this interface. */ iplite_if_lock(netif); IPLITE_CODE_UNLOCK(); nc = netif->nc_list; while (nc != IP_NULL) { addr.sin6_addr = nc->addr; if (IP_IN6_IS_ADDR_LINK_LOCAL(&nc->addr)) addr.sin6_scope_id = nc->netif->ipcom.ifindex; else addr.sin6_scope_id = 0; ipcom_printf("%-36s", ipcom_cmd_sockaddr_to_str((struct Ip_sockaddr *) &addr, IP_FALSE, IP_TRUE, str, sizeof(str))); ipcom_printf("%02x:%02x:%02x:%02x:%02x:%02x ", nc->link_addr[0], nc->link_addr[1], nc->link_addr[2], nc->link_addr[3], nc->link_addr[4], nc->link_addr[5]); ipcom_printf("%-6s", nc->netif->ipcom.name); ipcom_printf("%-10s", iplite_ndp_expire_time_str(nc->next_timeout, str)); ipcom_printf("%c", iplite_ndp_status_str((Ip_u16) nc->status)); ipcom_printf("\n"); nc = nc->next; } /* Unlock this interface, must be code locked to do that. */ IPLITE_CODE_LOCK(); (void)iplite_if_unlock(netif); /* Skip this interface. */ skip: IPLITE_CODE_UNLOCK(); } return 0; } /* *=========================================================================== * iplite_ndp_erase_all_neighbor_cache_entries *=========================================================================== * Description: Deletes all neighbor cache entries. * Parameters: * Returns: 0 = success, -1 = fail. * */ IP_STATIC int iplite_ndp_erase_all_neighbor_cache_entries(void) { Iplite_ip6_nc_entry *nc; Iplite_ip6_nc_entry *next_nc; Iplite_netif *netif; int i; IPLITE_CODE_LOCK(); for (i = 2; i < IPLITE_CONF_MAX_NETIF; i++) { netif = iplite.netifs[i]; if (netif == IP_NULL) continue; nc = netif->nc_list; while (nc != IP_NULL) { next_nc = nc->next; iplite_kfree(nc); nc = next_nc; } netif->nc_list = IP_NULL; } IPLITE_CODE_UNLOCK(); return 0; } /* *=========================================================================== * iplite_ndp_remove_neighbor_cache_entry *=========================================================================== * Description: Removes the specified ND entry from the ND cache. * Parameters: * str_ip6_addr - A string representation of the IPv6 address * of the entry to remove. * Returns: * */ IP_STATIC int iplite_ndp_remove_neighbor_cache_entry(IP_CONST char *str_ip6_addr) { Iplite_ip6_nc_entry **nc; struct Ip_sockaddr_in6 in6_addr; int i; Iplite_netif *netif; if (ipcom_getsockaddrbyaddrname(IP_AF_INET6, IP_TRUE, str_ip6_addr, (struct Ip_sockaddr *) &in6_addr) < 0) { ipcom_printf("%s is not a valid IPv6 address\n", str_ip6_addr); return -1; } IPLITE_CODE_LOCK(); for (i = 2; i < IPLITE_CONF_MAX_NETIF; i++) { netif = iplite.netifs[i]; if (netif == IP_NULL) continue; nc = &netif->nc_list; while (*nc != IP_NULL) { if (IP_IN6_ARE_ADDR_EQUAL(&(*nc)->addr, &in6_addr.sin6_addr)) { *nc = (*nc)->next; IPLITE_CODE_UNLOCK(); return 0; } nc = &(*nc)->next; } } IPLITE_CODE_UNLOCK(); ipcom_printf("%s was not found in the neighbor cache\n", str_ip6_addr); return -1; } /* *=========================================================================== * iplite_ndp_print_default_router_entries *=========================================================================== * Description: Prints all routers that has announced themself. * Parameters: * Returns: 0 = success, -1 = fail. * */ IP_STATIC int iplite_ndp_print_default_router_entries(void) { Iplite_ip6_dr_entry *dr; char str[40]; Iplite_netif *netif; int i; ipcom_printf("%-36s%-10s%-8s\n", "Router address", "Expire", "Netif"); for (i = 2; i < IPLITE_CONF_MAX_NETIF; i++) { IPLITE_CODE_LOCK(); netif = iplite.netifs[i]; if (netif == IP_NULL) goto skip; /* Lock this interface. */ iplite_if_lock(netif); IPLITE_CODE_UNLOCK(); dr = &netif->dr; if (dr->is_set) { ipcom_printf("%-36s", ipcom_inet_ntop(IP_AF_INET6, &dr->addr, str, sizeof(str))); ipcom_printf("%-10s", iplite_ndp_expire_time_str(dr->expires_sec, str)); ipcom_printf("%-8s", netif->ipcom.name); ipcom_printf("\n"); } /* Unlock this interface, must be code locked to do that. */ IPLITE_CODE_LOCK(); (void)iplite_if_unlock(netif); /* Skip this interface. */ skip: IPLITE_CODE_UNLOCK(); } return 0; } /* *=========================================================================== * iplite_ndp_remove_all_default_router_entries *=========================================================================== * Description: Remove all default router entries. * Parameters: * Returns: 0 = success, -1 = fail. * */ IP_STATIC int iplite_ndp_remove_all_default_router_entries(void) { Iplite_ip6_dr_entry *dr; Iplite_netif *netif; int i; IPLITE_CODE_LOCK(); for (i = 2; i < IPLITE_CONF_MAX_NETIF; i++) { netif = iplite.netifs[i]; if (netif == IP_NULL) continue; dr = &netif->dr; if (dr->is_set) dr->is_set = IP_FALSE; } IPLITE_CODE_UNLOCK(); return 0; } /* *=========================================================================== * iplite_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 iplite_ndp_add_entry(Ip_u32 ifindex, IP_CONST char *str_ip6_addr, IP_CONST char *str_link_addr) { Iplite_netif *netif; struct Ip_sockaddr_in6 ip6_addr; struct Ip_sockaddr_dl link_addr; Iplite_ip6_nc_entry *nc; if (ifindex < 2 || ifindex >= IPLITE_CONF_MAX_NETIF) { ipcom_printf("invalid interface index: %ld" IP_LF, ifindex); return -IP_ERRNO_EINVAL; } IPLITE_CODE_LOCK(); netif = iplite.netifs[ifindex]; if (netif == IP_NULL) { IPLITE_CODE_UNLOCK(); ipcom_printf("no interface defined at index: %ld" IP_LF, ifindex); return -IP_ERRNO_EINVAL; } iplite_if_lock(netif); IPLITE_CODE_UNLOCK(); if (ipcom_getsockaddrbyaddrname(IP_AF_INET6, IP_TRUE, str_ip6_addr, (struct Ip_sockaddr *) &ip6_addr) < 0) { ipcom_printf("%s is not a valid IPv6 address\n", str_ip6_addr); goto errout; } if (ipcom_getsockaddrbyaddr(IP_AF_LINK, str_link_addr, (struct Ip_sockaddr *) &link_addr) < 0) { ipcom_printf("%s is not a valid link address for %s\n", str_link_addr, netif->ipcom.name); goto errout; } IPLITE_CODE_LOCK(); nc = iplite_ip6_neighbor_cache_find(netif, &ip6_addr.sin6_addr); IPLITE_CODE_UNLOCK(); if (nc->status != IPLITE_IP6_ND_INCOMPLETE) { ipcom_printf("entry for: %s already exists" IP_LF, str_ip6_addr); goto errout; } IPLITE_CODE_LOCK(); iplite_ip6_neighbor_cache_update(nc, IPLITE_IP6_ND_REACHABLE, link_addr.sdl_data); nc->next_timeout = IPCOM_ADDR_INFINITE; (void)iplite_if_unlock(netif); IPLITE_CODE_UNLOCK(); return 0; errout: ip_assert(netif); IPLITE_CODE_LOCK(); (void)iplite_if_unlock(netif); IPLITE_CODE_UNLOCK(); return -IP_ERRNO_EINVAL; } /* *=========================================================================== * iplite_ndp_print_usage *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void iplite_ndp_print_usage(void) { ipcom_printf(IP_LF "NAME" IP_LF " ndp - control/diagnose IPv6 neighbor discovery protocol" IP_LF IP_LF); ipcom_printf("SYNOPSIS" IP_LF " ndp -a" IP_LF " ndp -A" IP_LF " ndp -c" IP_LF " ndp -d hostaddress" IP_LF " ndp -r" IP_LF " ndp -R" IP_LF " ndp [-i ] -s nodeaddress ether_addr" IP_LF IP_LF); ipcom_printf("DESCRIPTION" IP_LF " The ndp command manipulates the address mapping table used by Neighbor" IP_LF " Discovery Protocol (NDP). It can take up to 1 minute before deleted" IP_LF " entries is removed, but they should be shown as 'expired' immediately." IP_LF IP_LF); ipcom_printf(" Options:"IP_LF " -i Specify interface. Selected by the stack otherwise."IP_LF IP_LF " Commands:" IP_LF " -a Dump the currently existing NDP entries." IP_LF " -A Erase all the NDP entries." IP_LF " -d Delete specified NDP entry." IP_LF " -r Show default router list." IP_LF " -R Flush all the entries in the default router list." IP_LF " -s Register a NDP entry for a node. The entry will be permanent." IP_LF "" IP_LF); } /* **************************************************************************** * 10 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iplite_cmd_ndp *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC int iplite_cmd_ndp(int argc, char **argv) { Ip_u32 ifindex = 0; int c; int ret = 17; Ipcom_getopt opt; /* Parse options */ ipcom_getopt_clear_r(&opt); while ((c = ipcom_getopt_r(argc, argv, "AHPRad:hprsi:", &opt)) != -1) { switch (c) { case 'i' : ifindex = ipcom_if_nametoindex(opt.optarg); if(ifindex == 0) { ipcom_printf("%s is not a valid interface."IP_LF, opt.optarg); goto done; } break; default: break; } } ipcom_getopt_clear_r(&opt); while ((c = ipcom_getopt_r(argc, argv, "AHPRad:hprsV:i:", &opt)) != -1) { switch (c) { case 'a': ret = iplite_ndp_print_neighbor_cache_entries(); break; case 'A': ret = iplite_ndp_erase_all_neighbor_cache_entries(); break; case 'd': ret = iplite_ndp_remove_neighbor_cache_entry(opt.optarg); break; case 'r': ret = iplite_ndp_print_default_router_entries(); break; case 'R': ret = iplite_ndp_remove_all_default_router_entries(); break; case 's': if (argc < opt.optind + 2) goto done; ret = iplite_ndp_add_entry(ifindex, argv[opt.optind], argv[opt.optind+1]); break; default: break; } } done: if (ret == 17) iplite_ndp_print_usage(); ipcom_printf(IP_LF); return ret; } #endif /* IPCOM_USE_INET6 */ /* **************************************************************************** * END OF FILE **************************************************************************** */