Files
2026-07-30 11:19:44 +05:30

596 lines
17 KiB
C

/*
******************************************************************************
* 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 <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 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 <ipcom_clib.h>
#include <ipcom_cmd.h>
#include <ipcom_getopt.h>
#include <ipcom_inet.h>
#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 <ifname>] -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 <ifname> 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
****************************************************************************
*/