596 lines
17 KiB
C
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
|
|
****************************************************************************
|
|
*/
|
|
|