2017-07-06 17:29:42 +00:00
/*
* Copyright ( c ) 2017 , Inria .
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
* This file is part of the Contiki operating system .
*
*/
/**
* \ file
* The Contiki shell commands
* \ author
* Simon Duquennoy < simon . duquennoy @ inria . fr >
*/
/**
* \ addtogroup shell
* @ {
*/
# include "contiki.h"
# include "shell.h"
# include "shell-commands.h"
2018-06-08 10:16:49 +00:00
# include "lib/list.h"
2017-07-06 17:43:44 +00:00
# include "sys/log.h"
2017-07-14 14:47:11 +00:00
# include "dev/watchdog.h"
2017-09-22 13:06:44 +00:00
# include "net/ipv6/uip.h"
# include "net/ipv6/uiplib.h"
2017-07-06 17:29:42 +00:00
# include "net/ipv6/uip-icmp6.h"
2017-07-07 13:12:23 +00:00
# include "net/ipv6/uip-ds6.h"
2017-10-11 15:26:39 +00:00
# if MAC_CONF_WITH_TSCH
2017-07-10 15:45:07 +00:00
# include "net/mac/tsch/tsch.h"
2017-10-11 15:26:39 +00:00
# endif /* MAC_CONF_WITH_TSCH */
2017-12-09 08:53:48 +00:00
# include "net/routing/routing.h"
2017-10-12 13:34:06 +00:00
# include "net/mac/llsec802154.h"
2017-12-09 16:29:28 +00:00
2017-12-10 15:51:01 +00:00
/* For RPL-specific commands */
2017-12-10 20:20:24 +00:00
# if ROUTING_CONF_RPL_LITE
2017-12-10 15:51:01 +00:00
# include "net/routing/rpl-lite/rpl.h"
2017-12-10 20:20:24 +00:00
# elif ROUTING_CONF_RPL_CLASSIC
2017-12-10 15:51:01 +00:00
# include "net/routing/rpl-classic/rpl.h"
# endif
2017-07-06 17:43:44 +00:00
# include <stdlib.h>
2017-07-06 17:29:42 +00:00
# define PING_TIMEOUT (5 * CLOCK_SECOND)
static struct uip_icmp6_echo_reply_notification echo_reply_notification ;
static shell_output_func * curr_ping_output_func = NULL ;
static struct process * curr_ping_process ;
2017-07-07 13:43:31 +00:00
static uint8_t curr_ping_ttl ;
static uint16_t curr_ping_datalen ;
2017-09-14 12:48:08 +00:00
# if TSCH_WITH_SIXTOP
static shell_command_6top_sub_cmd_t sixtop_sub_cmd = NULL ;
# endif /* TSCH_WITH_SIXTOP */
2018-06-08 10:16:49 +00:00
static struct shell_command_set_t builtin_shell_command_set ;
LIST ( shell_command_sets ) ;
2017-07-15 10:35:59 +00:00
/*---------------------------------------------------------------------------*/
static const char *
ds6_nbr_state_to_str ( uint8_t state )
{
switch ( state ) {
case NBR_INCOMPLETE :
return " Incomplete " ;
case NBR_REACHABLE :
return " Reachable " ;
case NBR_STALE :
return " Stale " ;
case NBR_DELAY :
return " Delay " ;
case NBR_PROBE :
return " Probe " ;
default :
return " Unknown " ;
}
}
2017-12-10 20:20:24 +00:00
# if ROUTING_CONF_RPL_LITE
2017-07-10 15:45:07 +00:00
/*---------------------------------------------------------------------------*/
static const char *
rpl_state_to_str ( enum rpl_dag_state state )
{
switch ( state ) {
case DAG_INITIALIZED :
return " Initialized " ;
case DAG_JOINED :
return " Joined " ;
case DAG_REACHABLE :
return " Reachable " ;
case DAG_POISONING :
return " Poisoning " ;
default :
return " Unknown " ;
}
}
/*---------------------------------------------------------------------------*/
static const char *
rpl_mop_to_str ( int mop )
{
switch ( mop ) {
case RPL_MOP_NO_DOWNWARD_ROUTES :
return " No downward routes " ;
case RPL_MOP_NON_STORING :
return " Non-storing " ;
case RPL_MOP_STORING_NO_MULTICAST :
return " Storing " ;
case RPL_MOP_STORING_MULTICAST :
return " Storing+multicast " ;
default :
return " Unknown " ;
}
}
/*---------------------------------------------------------------------------*/
static const char *
rpl_ocp_to_str ( int ocp )
{
switch ( ocp ) {
case RPL_OCP_OF0 :
return " OF0 " ;
case RPL_OCP_MRHOF :
return " MRHOF " ;
default :
return " Unknown " ;
}
}
2017-12-10 19:51:26 +00:00
/*---------------------------------------------------------------------------*/
static
2018-05-15 19:21:51 +00:00
PT_THREAD ( cmd_rpl_nbr ( struct pt * pt , shell_output_func output , char * args ) )
{
PT_BEGIN ( pt ) ;
if ( ! curr_instance . used | | rpl_neighbor_count ( ) = = 0 ) {
SHELL_OUTPUT ( output , " RPL neighbors: none \n " ) ;
} else {
rpl_nbr_t * nbr = nbr_table_head ( rpl_neighbors ) ;
SHELL_OUTPUT ( output , " RPL neighbors: \n " ) ;
while ( nbr ! = NULL ) {
char buf [ 120 ] ;
rpl_neighbor_snprint ( buf , sizeof ( buf ) , nbr ) ;
SHELL_OUTPUT ( output , " %s \n " , buf ) ;
nbr = nbr_table_next ( rpl_neighbors , nbr ) ;
}
}
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
static
2017-12-10 19:51:26 +00:00
PT_THREAD ( cmd_rpl_status ( struct pt * pt , shell_output_func output , char * args ) )
{
PT_BEGIN ( pt ) ;
SHELL_OUTPUT ( output , " RPL status: \n " ) ;
if ( ! curr_instance . used ) {
SHELL_OUTPUT ( output , " -- Instance: None \n " ) ;
} else {
SHELL_OUTPUT ( output , " -- Instance: %u \n " , curr_instance . instance_id ) ;
if ( NETSTACK_ROUTING . node_is_root ( ) ) {
SHELL_OUTPUT ( output , " -- DAG root \n " ) ;
} else {
SHELL_OUTPUT ( output , " -- DAG node \n " ) ;
}
SHELL_OUTPUT ( output , " -- DAG: " ) ;
shell_output_6addr ( output , & curr_instance . dag . dag_id ) ;
SHELL_OUTPUT ( output , " , version %u \n " , curr_instance . dag . version ) ;
SHELL_OUTPUT ( output , " -- Prefix: " ) ;
shell_output_6addr ( output , & curr_instance . dag . prefix_info . prefix ) ;
SHELL_OUTPUT ( output , " /%u \n " , curr_instance . dag . prefix_info . length ) ;
SHELL_OUTPUT ( output , " -- MOP: %s \n " , rpl_mop_to_str ( curr_instance . mop ) ) ;
SHELL_OUTPUT ( output , " -- OF: %s \n " , rpl_ocp_to_str ( curr_instance . of - > ocp ) ) ;
SHELL_OUTPUT ( output , " -- Hop rank increment: %u \n " , curr_instance . min_hoprankinc ) ;
SHELL_OUTPUT ( output , " -- Default lifetime: %lu seconds \n " , RPL_LIFETIME ( curr_instance . default_lifetime ) ) ;
SHELL_OUTPUT ( output , " -- State: %s \n " , rpl_state_to_str ( curr_instance . dag . state ) ) ;
SHELL_OUTPUT ( output , " -- Preferred parent: " ) ;
2018-05-04 07:09:15 +00:00
if ( curr_instance . dag . preferred_parent ) {
shell_output_6addr ( output , rpl_neighbor_get_ipaddr ( curr_instance . dag . preferred_parent ) ) ;
SHELL_OUTPUT ( output , " (last DTSN: %u) \n " , curr_instance . dag . preferred_parent - > dtsn ) ;
} else {
SHELL_OUTPUT ( output , " None \n " ) ;
}
2017-12-10 19:51:26 +00:00
SHELL_OUTPUT ( output , " -- Rank: %u \n " , curr_instance . dag . rank ) ;
SHELL_OUTPUT ( output , " -- Lowest rank: %u (%u) \n " , curr_instance . dag . lowest_rank , curr_instance . max_rankinc ) ;
SHELL_OUTPUT ( output , " -- DTSN out: %u \n " , curr_instance . dtsn_out ) ;
SHELL_OUTPUT ( output , " -- DAO sequence: last sent %u, last acked %u \n " ,
curr_instance . dag . dao_last_seqno , curr_instance . dag . dao_last_acked_seqno ) ;
SHELL_OUTPUT ( output , " -- Trickle timer: current %u, min %u, max %u, redundancy %u \n " ,
curr_instance . dag . dio_intcurrent , curr_instance . dio_intmin ,
curr_instance . dio_intmin + curr_instance . dio_intdoubl , curr_instance . dio_redundancy ) ;
}
PT_END ( pt ) ;
}
2017-12-10 20:20:24 +00:00
# endif /* ROUTING_CONF_RPL_LITE */
2017-07-06 17:29:42 +00:00
/*---------------------------------------------------------------------------*/
static void
echo_reply_handler ( uip_ipaddr_t * source , uint8_t ttl , uint8_t * data , uint16_t datalen )
{
if ( curr_ping_output_func ! = NULL ) {
curr_ping_output_func = NULL ;
2017-07-07 13:43:31 +00:00
curr_ping_ttl = ttl ;
curr_ping_datalen = datalen ;
2017-07-06 17:29:42 +00:00
process_poll ( curr_ping_process ) ;
}
}
/*---------------------------------------------------------------------------*/
static
2017-07-07 13:11:51 +00:00
PT_THREAD ( cmd_ping ( struct pt * pt , shell_output_func output , char * args ) )
2017-07-06 17:29:42 +00:00
{
static uip_ipaddr_t remote_addr ;
static struct etimer timeout_timer ;
2017-07-07 13:11:51 +00:00
char * next_args ;
2017-07-06 17:29:42 +00:00
PT_BEGIN ( pt ) ;
2017-07-07 13:11:51 +00:00
SHELL_ARGS_INIT ( args , next_args ) ;
2017-07-06 17:29:42 +00:00
2017-07-07 13:11:51 +00:00
/* Get argument (remote IPv6) */
SHELL_ARGS_NEXT ( args , next_args ) ;
2018-03-22 17:38:56 +00:00
if ( args = = NULL ) {
SHELL_OUTPUT ( output , " Destination IPv6 address is not specified \n " ) ;
PT_EXIT ( pt ) ;
} else if ( uiplib_ipaddrconv ( args , & remote_addr ) = = 0 ) {
2018-03-22 17:42:21 +00:00
SHELL_OUTPUT ( output , " Invalid IPv6 address: %s \n " , args ) ;
2017-07-06 17:29:42 +00:00
PT_EXIT ( pt ) ;
}
SHELL_OUTPUT ( output , " Pinging " ) ;
shell_output_6addr ( output , & remote_addr ) ;
SHELL_OUTPUT ( output , " \n " ) ;
/* Send ping request */
curr_ping_process = PROCESS_CURRENT ( ) ;
curr_ping_output_func = output ;
etimer_set ( & timeout_timer , PING_TIMEOUT ) ;
uip_icmp6_send ( & remote_addr , ICMP6_ECHO_REQUEST , 0 , 4 ) ;
PT_WAIT_UNTIL ( pt , curr_ping_output_func = = NULL | | etimer_expired ( & timeout_timer ) ) ;
if ( curr_ping_output_func ! = NULL ) {
SHELL_OUTPUT ( output , " Timeout \n " ) ;
curr_ping_output_func = NULL ;
2017-07-07 13:43:31 +00:00
} else {
SHELL_OUTPUT ( output , " Received ping reply from " ) ;
shell_output_6addr ( output , & remote_addr ) ;
2017-07-07 16:05:27 +00:00
SHELL_OUTPUT ( output , " , len %u, ttl %u, delay %lu ms \n " ,
curr_ping_datalen , curr_ping_ttl , ( 1000 * ( clock_time ( ) - timeout_timer . timer . start ) ) / CLOCK_SECOND ) ;
2017-07-06 17:29:42 +00:00
}
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
2017-07-15 13:19:09 +00:00
static void
shell_output_log_levels ( shell_output_func output )
{
int i = 0 ;
SHELL_OUTPUT ( output , " Log levels: \n " ) ;
while ( all_modules [ i ] . name ! = NULL ) {
2017-10-11 15:26:39 +00:00
SHELL_OUTPUT ( output , " -- %-10s: %u (%s) \n " ,
2017-07-15 13:19:09 +00:00
all_modules [ i ] . name ,
2017-10-11 15:26:39 +00:00
* all_modules [ i ] . curr_log_level ,
2017-07-15 13:19:09 +00:00
log_level_to_str ( * all_modules [ i ] . curr_log_level ) ) ;
i + + ;
}
}
/*---------------------------------------------------------------------------*/
2017-07-06 17:43:44 +00:00
static
2017-07-07 13:11:51 +00:00
PT_THREAD ( cmd_log ( struct pt * pt , shell_output_func output , char * args ) )
2017-07-06 17:29:42 +00:00
{
2017-07-07 13:11:51 +00:00
static int prev_level ;
static int level ;
char * next_args ;
char * ptr ;
2017-07-15 13:19:09 +00:00
char * module ;
2017-07-07 13:11:51 +00:00
2017-07-06 17:29:42 +00:00
PT_BEGIN ( pt ) ;
2017-07-07 13:11:51 +00:00
SHELL_ARGS_INIT ( args , next_args ) ;
2017-07-15 13:19:09 +00:00
/* Get and parse argument: module name */
SHELL_ARGS_NEXT ( args , next_args ) ;
module = args ;
prev_level = log_get_level ( module ) ;
if ( module = = NULL | | ( strcmp ( " all " , module ) & & prev_level = = - 1 ) ) {
SHELL_OUTPUT ( output , " Invalid first argument: %s \n " , module )
shell_output_log_levels ( output ) ;
PT_EXIT ( pt ) ;
}
/* Get and parse argument: log level */
2017-07-07 13:11:51 +00:00
SHELL_ARGS_NEXT ( args , next_args ) ;
2017-07-10 14:32:41 +00:00
if ( args = = NULL ) {
level = - 1 ;
} else {
level = ( int ) strtol ( args , & ptr , 10 ) ;
}
2017-07-07 13:11:51 +00:00
if ( ( level = = 0 & & args = = ptr )
| | level < LOG_LEVEL_NONE | | level > LOG_LEVEL_DBG ) {
2017-07-15 13:19:09 +00:00
SHELL_OUTPUT ( output , " Invalid second argument: %s \n " , args ) ;
2017-07-07 13:11:51 +00:00
PT_EXIT ( pt ) ;
}
/* Set log level */
if ( level ! = prev_level ) {
2017-07-15 13:19:09 +00:00
log_set_level ( module , level ) ;
2017-10-12 10:23:32 +00:00
# if MAC_CONF_WITH_TSCH && TSCH_LOG_PER_SLOT
2017-07-15 13:19:09 +00:00
if ( ! strcmp ( module , " mac " ) | | ! strcmp ( module , " all " ) ) {
if ( level > = LOG_LEVEL_DBG ) {
tsch_log_init ( ) ;
SHELL_OUTPUT ( output , " TSCH logging started \n " ) ;
} else {
tsch_log_stop ( ) ;
SHELL_OUTPUT ( output , " TSCH logging stopped \n " ) ;
}
2017-07-07 13:11:51 +00:00
}
2017-10-12 10:23:32 +00:00
# endif /* MAC_CONF_WITH_TSCH && TSCH_LOG_PER_SLOT */
2017-07-07 13:11:51 +00:00
}
2017-07-15 13:19:09 +00:00
shell_output_log_levels ( output ) ;
2017-07-07 13:11:51 +00:00
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_help ( struct pt * pt , shell_output_func output , char * args ) )
{
2018-06-08 10:16:49 +00:00
struct shell_command_set_t * set ;
const struct shell_command_t * cmd ;
2017-07-07 13:11:51 +00:00
PT_BEGIN ( pt ) ;
2017-07-06 17:29:42 +00:00
SHELL_OUTPUT ( output , " Available commands: \n " ) ;
2018-06-08 10:16:49 +00:00
/* Note: we explicitly don't expend any code space to deal with shadowing */
for ( set = list_head ( shell_command_sets ) ; set ! = NULL ; set = list_item_next ( set ) ) {
for ( cmd = set - > commands ; cmd - > name ! = NULL ; + + cmd ) {
SHELL_OUTPUT ( output , " %s \n " , cmd - > help ) ;
}
2017-07-06 17:29:42 +00:00
}
PT_END ( pt ) ;
}
2018-03-26 18:51:30 +00:00
# if UIP_CONF_IPV6_RPL
2017-10-12 13:42:00 +00:00
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_rpl_set_root ( struct pt * pt , shell_output_func output , char * args ) )
{
static int is_on ;
static uip_ipaddr_t prefix ;
char * next_args ;
PT_BEGIN ( pt ) ;
SHELL_ARGS_INIT ( args , next_args ) ;
/* Get first arg (0/1) */
SHELL_ARGS_NEXT ( args , next_args ) ;
if ( ! strcmp ( args , " 1 " ) ) {
is_on = 1 ;
} else if ( ! strcmp ( args , " 0 " ) ) {
is_on = 0 ;
} else {
SHELL_OUTPUT ( output , " Invalid argument: %s \n " , args ) ;
PT_EXIT ( pt ) ;
}
/* Get first second arg (prefix) */
SHELL_ARGS_NEXT ( args , next_args ) ;
if ( args ! = NULL ) {
if ( uiplib_ipaddrconv ( args , & prefix ) = = 0 ) {
SHELL_OUTPUT ( output , " Invalid Prefix: %s \n " , args ) ;
PT_EXIT ( pt ) ;
}
} else {
uip_ip6addr ( & prefix , UIP_DS6_DEFAULT_PREFIX , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
}
if ( is_on ) {
2017-12-10 19:51:26 +00:00
if ( ! NETSTACK_ROUTING . node_is_root ( ) ) {
2017-10-12 13:42:00 +00:00
SHELL_OUTPUT ( output , " Setting as DAG root with prefix " ) ;
shell_output_6addr ( output , & prefix ) ;
SHELL_OUTPUT ( output , " /64 \n " ) ;
2017-12-09 13:19:01 +00:00
NETSTACK_ROUTING . root_set_prefix ( & prefix , NULL ) ;
2017-12-09 13:23:35 +00:00
NETSTACK_ROUTING . root_start ( ) ;
2017-10-12 13:42:00 +00:00
} else {
SHELL_OUTPUT ( output , " Node is already a DAG root \n " ) ;
}
} else {
2017-12-10 19:51:26 +00:00
if ( NETSTACK_ROUTING . node_is_root ( ) ) {
2017-10-12 13:42:00 +00:00
SHELL_OUTPUT ( output , " Setting as non-root node: leaving DAG \n " ) ;
2017-12-10 19:51:26 +00:00
NETSTACK_ROUTING . leave_network ( ) ;
2017-10-12 13:42:00 +00:00
} else {
SHELL_OUTPUT ( output , " Node is not a DAG root \n " ) ;
}
}
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
static
2017-07-10 15:45:07 +00:00
PT_THREAD ( cmd_rpl_global_repair ( struct pt * pt , shell_output_func output , char * args ) )
{
PT_BEGIN ( pt ) ;
2017-12-09 16:45:10 +00:00
SHELL_OUTPUT ( output , " Triggering routing global repair \n " )
NETSTACK_ROUTING . global_repair ( " Shell " ) ;
2017-07-10 15:45:07 +00:00
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_rpl_local_repair ( struct pt * pt , shell_output_func output , char * args ) )
{
PT_BEGIN ( pt ) ;
2017-12-09 16:45:10 +00:00
SHELL_OUTPUT ( output , " Triggering routing local repair \n " ) ;
NETSTACK_ROUTING . local_repair ( " Shell " ) ;
2017-07-10 15:45:07 +00:00
PT_END ( pt ) ;
}
2018-04-05 15:54:08 +00:00
/*---------------------------------------------------------------------------*/
2018-05-04 07:49:27 +00:00
# if ROUTING_CONF_RPL_LITE
2018-04-05 15:54:08 +00:00
static
PT_THREAD ( cmd_rpl_refresh_routes ( struct pt * pt , shell_output_func output , char * args ) )
{
PT_BEGIN ( pt ) ;
SHELL_OUTPUT ( output , " Triggering routes refresh \n " )
rpl_refresh_routes ( " Shell " ) ;
PT_END ( pt ) ;
}
2018-05-04 07:49:27 +00:00
# endif /* ROUTING_CONF_RPL_LITE */
2018-03-26 18:51:30 +00:00
# endif /* UIP_CONF_IPV6_RPL */
2017-07-10 15:45:07 +00:00
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_ipaddr ( struct pt * pt , shell_output_func output , char * args ) )
2017-07-07 16:05:27 +00:00
{
int i ;
uint8_t state ;
PT_BEGIN ( pt ) ;
SHELL_OUTPUT ( output , " Node IPv6 addresses: \n " ) ;
for ( i = 0 ; i < UIP_DS6_ADDR_NB ; i + + ) {
state = uip_ds6_if . addr_list [ i ] . state ;
if ( uip_ds6_if . addr_list [ i ] . isused & &
( state = = ADDR_TENTATIVE | | state = = ADDR_PREFERRED ) ) {
SHELL_OUTPUT ( output , " -- " ) ;
shell_output_6addr ( output , & uip_ds6_if . addr_list [ i ] . ipaddr ) ;
SHELL_OUTPUT ( output , " \n " ) ;
}
}
2017-07-10 15:45:07 +00:00
PT_END ( pt ) ;
2017-07-15 10:35:59 +00:00
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_ip_neighbors ( struct pt * pt , shell_output_func output , char * args ) )
{
uip_ds6_nbr_t * nbr ;
PT_BEGIN ( pt ) ;
nbr = uip_ds6_nbr_head ( ) ;
if ( nbr = = NULL ) {
SHELL_OUTPUT ( output , " Node IPv6 neighbors: none \n " ) ;
PT_EXIT ( pt ) ;
}
SHELL_OUTPUT ( output , " Node IPv6 neighbors: \n " ) ;
while ( nbr ! = NULL ) {
SHELL_OUTPUT ( output , " -- " ) ;
shell_output_6addr ( output , uip_ds6_nbr_get_ipaddr ( nbr ) ) ;
SHELL_OUTPUT ( output , " <-> " ) ;
shell_output_lladdr ( output , ( linkaddr_t * ) uip_ds6_nbr_get_ll ( nbr ) ) ;
SHELL_OUTPUT ( output , " , router %u, state %s " ,
nbr - > isrouter , ds6_nbr_state_to_str ( nbr - > state ) ) ;
SHELL_OUTPUT ( output , " \n " ) ;
nbr = uip_ds6_nbr_next ( nbr ) ;
}
PT_END ( pt ) ;
2017-07-10 15:45:07 +00:00
}
2017-10-11 15:26:39 +00:00
# if MAC_CONF_WITH_TSCH
2017-07-10 15:45:07 +00:00
/*---------------------------------------------------------------------------*/
static
2017-10-12 12:55:25 +00:00
PT_THREAD ( cmd_tsch_set_coordinator ( struct pt * pt , shell_output_func output , char * args ) )
{
static int is_on ;
2017-10-12 13:34:06 +00:00
static int is_secured ;
2017-10-12 12:55:25 +00:00
char * next_args ;
PT_BEGIN ( pt ) ;
SHELL_ARGS_INIT ( args , next_args ) ;
/* Get first arg (0/1) */
SHELL_ARGS_NEXT ( args , next_args ) ;
if ( ! strcmp ( args , " 1 " ) ) {
is_on = 1 ;
} else if ( ! strcmp ( args , " 0 " ) ) {
is_on = 0 ;
} else {
2017-10-12 13:34:06 +00:00
SHELL_OUTPUT ( output , " Invalid first argument: %s \n " , args ) ;
2017-10-12 12:55:25 +00:00
PT_EXIT ( pt ) ;
}
2017-10-12 13:34:06 +00:00
/* Get first second arg (prefix) */
SHELL_ARGS_NEXT ( args , next_args ) ;
if ( args ! = NULL ) {
if ( ! strcmp ( args , " 1 " ) ) {
# if LLSEC802154_ENABLED
is_secured = 1 ;
# else /* LLSEC802154_ENABLED */
SHELL_OUTPUT ( output , " Security is not compiled in. \n " ) ;
is_secured = 0 ;
# endif /* LLSEC802154_ENABLED */
} else if ( ! strcmp ( args , " 0 " ) ) {
is_secured = 0 ;
} else {
SHELL_OUTPUT ( output , " Invalid second argument: %s \n " , args ) ;
PT_EXIT ( pt ) ;
}
} else {
is_secured = 0 ;
}
SHELL_OUTPUT ( output , " Setting as TSCH %s (%s) \n " ,
is_on ? " coordinator " : " non-coordinator " , is_secured ? " secured " : " non-secured " ) ;
tsch_set_pan_secured ( is_secured ) ;
2017-10-12 12:55:25 +00:00
tsch_set_coordinator ( is_on ) ;
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
static
2017-07-10 15:45:07 +00:00
PT_THREAD ( cmd_tsch_status ( struct pt * pt , shell_output_func output , char * args ) )
{
PT_BEGIN ( pt ) ;
SHELL_OUTPUT ( output , " TSCH status: \n " ) ;
SHELL_OUTPUT ( output , " -- Is coordinator: %u \n " , tsch_is_coordinator ) ;
SHELL_OUTPUT ( output , " -- Is associated: %u \n " , tsch_is_associated ) ;
if ( tsch_is_associated ) {
struct tsch_neighbor * n = tsch_queue_get_time_source ( ) ;
SHELL_OUTPUT ( output , " -- PAN ID: 0x%x \n " , frame802154_get_pan_id ( ) ) ;
SHELL_OUTPUT ( output , " -- Is PAN secured: %u \n " , tsch_is_pan_secured ) ;
SHELL_OUTPUT ( output , " -- Join priority: %u \n " , tsch_join_priority ) ;
SHELL_OUTPUT ( output , " -- Time source: " ) ;
if ( n ! = NULL ) {
shell_output_lladdr ( output , & n - > addr ) ;
SHELL_OUTPUT ( output , " \n " ) ;
} else {
SHELL_OUTPUT ( output , " none \n " ) ;
}
SHELL_OUTPUT ( output , " -- Last synchronized: %lu seconds ago \n " , ( clock_time ( ) - last_sync_time ) / CLOCK_SECOND ) ;
SHELL_OUTPUT ( output , " -- Drift w.r.t. coordinator: %ld ppm \n " , tsch_adaptive_timesync_get_drift_ppm ( ) ) ;
}
PT_END ( pt ) ;
}
2017-10-11 15:26:39 +00:00
# endif /* MAC_CONF_WITH_TSCH */
2017-07-10 15:45:07 +00:00
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_routes ( struct pt * pt , shell_output_func output , char * args ) )
2017-07-07 16:05:27 +00:00
{
uip_ds6_defrt_t * default_route ;
PT_BEGIN ( pt ) ;
/* Our default route */
SHELL_OUTPUT ( output , " Default route: \n " ) ;
default_route = uip_ds6_defrt_lookup ( uip_ds6_defrt_choose ( ) ) ;
if ( default_route ! = NULL ) {
SHELL_OUTPUT ( output , " -- " ) ;
shell_output_6addr ( output , & default_route - > ipaddr ) ;
if ( default_route - > lifetime . interval ! = 0 ) {
SHELL_OUTPUT ( output , " (lifetime: %lu seconds) \n " , ( unsigned long ) default_route - > lifetime . interval ) ;
} else {
SHELL_OUTPUT ( output , " (lifetime: infinite) \n " ) ;
}
} else {
SHELL_OUTPUT ( output , " -- None \n " ) ;
}
2017-12-10 20:59:00 +00:00
# if UIP_CONF_IPV6_RPL
2017-12-13 20:00:33 +00:00
if ( uip_sr_num_nodes ( ) > 0 ) {
uip_sr_node_t * link ;
2017-07-07 16:05:27 +00:00
/* Our routing links */
2017-12-13 20:00:33 +00:00
SHELL_OUTPUT ( output , " Routing links (%u in total): \n " , uip_sr_num_nodes ( ) ) ;
link = uip_sr_node_head ( ) ;
2017-07-07 16:05:27 +00:00
while ( link ! = NULL ) {
2018-05-18 12:52:55 +00:00
char buf [ 100 ] ;
uip_sr_link_snprint ( buf , sizeof ( buf ) , link ) ;
SHELL_OUTPUT ( output , " -- %s \n " , buf ) ;
2017-12-13 20:00:33 +00:00
link = uip_sr_node_next ( link ) ;
2017-07-07 16:05:27 +00:00
}
} else {
SHELL_OUTPUT ( output , " No routing links \n " ) ;
}
2017-12-10 20:59:00 +00:00
# endif /* UIP_CONF_IPV6_RPL */
2017-07-07 16:05:27 +00:00
2017-12-10 19:51:26 +00:00
# if (UIP_MAX_ROUTES != 0)
2017-07-07 16:05:27 +00:00
if ( uip_ds6_route_num_routes ( ) > 0 ) {
2017-12-10 20:59:00 +00:00
uip_ds6_route_t * route ;
2017-07-07 16:05:27 +00:00
/* Our routing entries */
SHELL_OUTPUT ( output , " Routing entries (%u in total): \n " , uip_ds6_route_num_routes ( ) ) ;
route = uip_ds6_route_head ( ) ;
while ( route ! = NULL ) {
SHELL_OUTPUT ( output , " -- " ) ;
shell_output_6addr ( output , & route - > ipaddr ) ;
SHELL_OUTPUT ( output , " via " ) ;
shell_output_6addr ( output , uip_ds6_route_nexthop ( route ) ) ;
2017-12-10 19:51:26 +00:00
if ( ( unsigned long ) route - > state . lifetime ! = 0xFFFFFFFF ) {
2017-07-07 16:05:27 +00:00
SHELL_OUTPUT ( output , " (lifetime: %lu seconds) \n " , ( unsigned long ) route - > state . lifetime ) ;
} else {
SHELL_OUTPUT ( output , " (lifetime: infinite) \n " ) ;
}
route = uip_ds6_route_next ( route ) ;
}
} else {
SHELL_OUTPUT ( output , " No routing entries \n " ) ;
}
2017-12-10 19:51:26 +00:00
# endif /* (UIP_MAX_ROUTES != 0) */
2017-07-07 16:05:27 +00:00
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
2017-07-15 07:49:39 +00:00
static
2017-07-14 14:47:11 +00:00
PT_THREAD ( cmd_reboot ( struct pt * pt , shell_output_func output , char * args ) )
{
PT_BEGIN ( pt ) ;
SHELL_OUTPUT ( output , " rebooting \n " ) ;
watchdog_reboot ( ) ;
PT_END ( pt ) ;
}
2017-10-11 15:26:39 +00:00
# if MAC_CONF_WITH_TSCH
/*---------------------------------------------------------------------------*/
2017-07-14 14:47:11 +00:00
static
2017-07-15 07:49:39 +00:00
PT_THREAD ( cmd_tsch_schedule ( struct pt * pt , shell_output_func output , char * args ) )
{
struct tsch_slotframe * sf ;
PT_BEGIN ( pt ) ;
if ( tsch_is_locked ( ) ) {
PT_EXIT ( pt ) ;
}
sf = tsch_schedule_slotframe_head ( ) ;
if ( sf = = NULL ) {
SHELL_OUTPUT ( output , " TSCH schedule: no slotframe \n " ) ;
} else {
SHELL_OUTPUT ( output , " TSCH schedule: \n " ) ;
while ( sf ! = NULL ) {
struct tsch_link * l = list_head ( sf - > links_list ) ;
SHELL_OUTPUT ( output , " -- Slotframe: handle %u, size %u, links: \n " , sf - > handle , sf - > size . val ) ;
while ( l ! = NULL ) {
SHELL_OUTPUT ( output , " ---- Options %02x, type %u, timeslot %u, channel offset %u, address " ,
l - > link_options , l - > link_type , l - > timeslot , l - > channel_offset ) ;
shell_output_lladdr ( output , & l - > addr ) ;
SHELL_OUTPUT ( output , " \n " ) ;
l = list_item_next ( l ) ;
}
sf = tsch_schedule_slotframe_next ( sf ) ;
}
}
PT_END ( pt ) ;
}
2017-10-11 15:26:39 +00:00
# endif /* MAC_CONF_WITH_TSCH */
2017-07-15 07:49:39 +00:00
/*---------------------------------------------------------------------------*/
2017-09-14 12:48:08 +00:00
# if TSCH_WITH_SIXTOP
void
shell_commands_set_6top_sub_cmd ( shell_command_6top_sub_cmd_t sub_cmd )
{
sixtop_sub_cmd = sub_cmd ;
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_6top ( struct pt * pt , shell_output_func output , char * args ) )
{
char * next_args ;
PT_BEGIN ( pt ) ;
SHELL_ARGS_INIT ( args , next_args ) ;
if ( sixtop_sub_cmd = = NULL ) {
SHELL_OUTPUT ( output , " 6top command is unavailable: \n " ) ;
} else {
SHELL_OUTPUT ( output , " 6top: " ) ;
sixtop_sub_cmd ( output , args ) ;
}
SHELL_ARGS_NEXT ( args , next_args ) ;
PT_END ( pt ) ;
}
# endif /* TSCH_WITH_SIXTOP */
/*---------------------------------------------------------------------------*/
2018-10-20 20:27:19 +00:00
# if LLSEC802154_ENABLED
static
PT_THREAD ( cmd_llsec_setlv ( struct pt * pt , shell_output_func output , char * args ) )
{
char * next_args ;
PT_BEGIN ( pt ) ;
SHELL_ARGS_INIT ( args , next_args ) ;
if ( args = = NULL ) {
SHELL_OUTPUT ( output , " Default LLSEC level is %d \n " ,
uipbuf_get_attr ( UIPBUF_ATTR_LLSEC_LEVEL ) ) ;
PT_EXIT ( pt ) ;
} else {
int lv = atoi ( args ) ;
if ( lv < 0 | | lv > 7 ) {
SHELL_OUTPUT ( output , " Illegal LLSEC Level %d \n " , lv ) ;
PT_EXIT ( pt ) ;
} else {
uipbuf_set_default_attr ( UIPBUF_ATTR_LLSEC_LEVEL , lv ) ;
uipbuf_clear_attr ( ) ;
SHELL_OUTPUT ( output , " LLSEC default level set %d \n " , lv ) ;
}
}
SHELL_ARGS_NEXT ( args , next_args ) ;
PT_END ( pt ) ;
}
/*---------------------------------------------------------------------------*/
static
PT_THREAD ( cmd_llsec_setkey ( struct pt * pt , shell_output_func output , char * args ) )
{
char * next_args ;
PT_BEGIN ( pt ) ;
SHELL_ARGS_INIT ( args , next_args ) ;
if ( args = = NULL ) {
SHELL_OUTPUT ( output , " Provide an index and a 16-char string for the key \n " ) ;
PT_EXIT ( pt ) ;
} else {
int key ;
SHELL_ARGS_NEXT ( args , next_args ) ;
key = atoi ( args ) ;
if ( key < 0 | | key > 16 ) {
SHELL_OUTPUT ( output , " Illegal LLSEC Key index %d \n " , key ) ;
PT_EXIT ( pt ) ;
} else {
# if MAC_CONF_WITH_CSMA
/* Get next arg (key-string) */
SHELL_ARGS_NEXT ( args , next_args ) ;
if ( args ! = NULL & & strlen ( args ) = = 16 ) {
csma_security_set_key ( key , ( uint8_t * ) args ) ;
SHELL_OUTPUT ( output , " Set key for index %d \n " , key ) ;
} else {
SHELL_OUTPUT ( output , " Wrong length of key: '%s' (%d) \n " , args , strlen ( args ) ) ;
}
# else
SHELL_OUTPUT ( output , " Set key not supported. \n " ) ;
PT_EXIT ( pt ) ;
# endif
}
}
PT_END ( pt ) ;
}
# endif /* LLSEC802154_ENABLED */
/*---------------------------------------------------------------------------*/
2017-07-06 17:29:42 +00:00
void
shell_commands_init ( void )
{
2018-06-08 10:16:49 +00:00
list_init ( shell_command_sets ) ;
list_add ( shell_command_sets , & builtin_shell_command_set ) ;
2017-07-06 17:29:42 +00:00
/* Set up Ping Reply callback */
uip_icmp6_echo_reply_callback_add ( & echo_reply_notification ,
echo_reply_handler ) ;
}
/*---------------------------------------------------------------------------*/
2018-06-08 10:16:49 +00:00
void
shell_command_set_register ( struct shell_command_set_t * set )
{
list_push ( shell_command_sets , set ) ;
}
/*---------------------------------------------------------------------------*/
int
shell_command_set_deregister ( struct shell_command_set_t * set )
{
if ( ! list_contains ( shell_command_sets , set ) ) {
return ! 0 ;
}
list_remove ( shell_command_sets , set ) ;
return 0 ;
}
/*---------------------------------------------------------------------------*/
const struct shell_command_t *
shell_command_lookup ( const char * name )
{
struct shell_command_set_t * set ;
const struct shell_command_t * cmd ;
for ( set = list_head ( shell_command_sets ) ;
set ! = NULL ;
set = list_item_next ( set ) ) {
for ( cmd = set - > commands ; cmd - > name ! = NULL ; + + cmd ) {
if ( ! strcmp ( cmd - > name , name ) ) {
return cmd ;
}
}
}
return NULL ;
}
/*---------------------------------------------------------------------------*/
const struct shell_command_t builtin_shell_commands [ ] = {
2017-07-10 15:45:07 +00:00
{ " help " , cmd_help , " '> help': Shows this help " } ,
2017-10-11 15:26:39 +00:00
{ " reboot " , cmd_reboot , " '> reboot': Reboot the board by watchdog_reboot() " } ,
2017-07-15 13:19:09 +00:00
{ " ip-addr " , cmd_ipaddr , " '> ip-addr': Shows all IPv6 addresses " } ,
{ " ip-nbr " , cmd_ip_neighbors , " '> ip-nbr': Shows all IPv6 neighbors " } ,
{ " log " , cmd_log , " '> log module level': Sets log level (0--4) for a given module (or \" all \" ). For module \" mac \" , level 4 also enables per-slot logging. " } ,
2017-07-10 15:45:07 +00:00
{ " ping " , cmd_ping , " '> ping addr': Pings the IPv6 address 'addr' " } ,
2017-12-10 19:51:26 +00:00
# if UIP_CONF_IPV6_RPL
2017-10-12 12:55:25 +00:00
{ " rpl-set-root " , cmd_rpl_set_root , " '> rpl-set-root 0/1 [prefix]': Sets node as root (1) or not (0). A /64 prefix can be optionally specified. " } ,
2017-07-10 15:45:07 +00:00
{ " rpl-local-repair " , cmd_rpl_local_repair , " '> rpl-local-repair': Triggers a RPL local repair " } ,
2018-05-04 07:49:27 +00:00
# if ROUTING_CONF_RPL_LITE
2018-04-05 15:54:08 +00:00
{ " rpl-refresh-routes " , cmd_rpl_refresh_routes , " '> rpl-refresh-routes': Refreshes all routes through a DTSN increment " } ,
2018-05-04 07:49:27 +00:00
# endif /* ROUTING_CONF_RPL_LITE */
2017-10-11 15:26:39 +00:00
{ " rpl-global-repair " , cmd_rpl_global_repair , " '> rpl-global-repair': Triggers a RPL global repair " } ,
2017-12-10 19:51:26 +00:00
# endif /* UIP_CONF_IPV6_RPL */
2017-12-10 20:20:24 +00:00
# if ROUTING_CONF_RPL_LITE
2017-12-10 19:51:26 +00:00
{ " rpl-status " , cmd_rpl_status , " '> rpl-status': Shows a summary of the current RPL state " } ,
2018-05-15 19:21:51 +00:00
{ " rpl-nbr " , cmd_rpl_nbr , " '> rpl-nbr': Shows the RPL neighbor table " } ,
2017-12-10 20:20:24 +00:00
# endif /* ROUTING_CONF_RPL_LITE */
2017-07-10 15:45:07 +00:00
{ " routes " , cmd_routes , " '> routes': Shows the route entries " } ,
2017-10-11 15:26:39 +00:00
# if MAC_CONF_WITH_TSCH
2017-10-12 13:34:06 +00:00
{ " tsch-set-coordinator " , cmd_tsch_set_coordinator , " '> tsch-set-coordinator 0/1 [0/1]': Sets node as coordinator (1) or not (0). Second, optional parameter: enable (1) or disable (0) security. " } ,
2017-07-15 07:49:39 +00:00
{ " tsch-schedule " , cmd_tsch_schedule , " '> tsch-schedule': Shows the current TSCH schedule " } ,
2017-07-10 15:45:07 +00:00
{ " tsch-status " , cmd_tsch_status , " '> tsch-status': Shows a summary of the current TSCH state " } ,
2017-10-11 15:26:39 +00:00
# endif /* MAC_CONF_WITH_TSCH */
2017-09-14 12:48:08 +00:00
# if TSCH_WITH_SIXTOP
{ " 6top " , cmd_6top , " '> 6top help': Shows 6top command usage " } ,
# endif /* TSCH_WITH_SIXTOP */
2018-10-20 20:27:19 +00:00
# if LLSEC802154_ENABLED
{ " llsec-set-level " , cmd_llsec_setlv , " '> llsec-set-level <lv>': Set the level of link layer security (show if no lv argument) " } ,
{ " llsec-set-key " , cmd_llsec_setkey , " '> llsec-set-key <id> <key>': Set the key of link layer security (show if no id key argument) " } ,
# endif /* LLSEC802154_ENABLED */
2017-07-06 17:29:42 +00:00
{ NULL , NULL , NULL } ,
} ;
2018-06-08 10:16:49 +00:00
static struct shell_command_set_t builtin_shell_command_set = {
. next = NULL ,
. commands = builtin_shell_commands ,
} ;
2017-07-06 17:29:42 +00:00
/** @} */