Contiki-NG
shell-commands.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017, Inria.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * The Contiki shell commands
36  * \author
37  * Simon Duquennoy <simon.duquennoy@inria.fr>
38  */
39 
40 /**
41  * \addtogroup shell
42  * @{
43  */
44 
45 #include "contiki.h"
46 #include "shell.h"
47 #include "shell-commands.h"
48 #include "lib/list.h"
49 #include "sys/log.h"
50 #include "dev/watchdog.h"
51 #include "net/ipv6/uip.h"
52 #include "net/ipv6/uiplib.h"
53 #include "net/ipv6/uip-icmp6.h"
54 #include "net/ipv6/uip-ds6.h"
55 #if MAC_CONF_WITH_TSCH
56 #include "net/mac/tsch/tsch.h"
57 #endif /* MAC_CONF_WITH_TSCH */
58 #include "net/routing/routing.h"
59 #include "net/mac/llsec802154.h"
60 
61 /* For RPL-specific commands */
62 #if ROUTING_CONF_RPL_LITE
63 #include "net/routing/rpl-lite/rpl.h"
64 #elif ROUTING_CONF_RPL_CLASSIC
65 #include "net/routing/rpl-classic/rpl.h"
66 #endif
67 
68 #include <stdlib.h>
69 
70 #define PING_TIMEOUT (5 * CLOCK_SECOND)
71 
72 static struct uip_icmp6_echo_reply_notification echo_reply_notification;
73 static shell_output_func *curr_ping_output_func = NULL;
74 static struct process *curr_ping_process;
75 static uint8_t curr_ping_ttl;
76 static uint16_t curr_ping_datalen;
77 #if TSCH_WITH_SIXTOP
78 static shell_command_6top_sub_cmd_t sixtop_sub_cmd = NULL;
79 #endif /* TSCH_WITH_SIXTOP */
80 static struct shell_command_set_t builtin_shell_command_set;
81 LIST(shell_command_sets);
82 /*---------------------------------------------------------------------------*/
83 static const char *
84 ds6_nbr_state_to_str(uint8_t state)
85 {
86  switch(state) {
87  case NBR_INCOMPLETE:
88  return "Incomplete";
89  case NBR_REACHABLE:
90  return "Reachable";
91  case NBR_STALE:
92  return "Stale";
93  case NBR_DELAY:
94  return "Delay";
95  case NBR_PROBE:
96  return "Probe";
97  default:
98  return "Unknown";
99  }
100 }
101 #if ROUTING_CONF_RPL_LITE
102 /*---------------------------------------------------------------------------*/
103 static const char *
104 rpl_state_to_str(enum rpl_dag_state state)
105 {
106  switch(state) {
107  case DAG_INITIALIZED:
108  return "Initialized";
109  case DAG_JOINED:
110  return "Joined";
111  case DAG_REACHABLE:
112  return "Reachable";
113  case DAG_POISONING:
114  return "Poisoning";
115  default:
116  return "Unknown";
117  }
118 }
119 /*---------------------------------------------------------------------------*/
120 static const char *
121 rpl_mop_to_str(int mop)
122 {
123  switch(mop) {
124  case RPL_MOP_NO_DOWNWARD_ROUTES:
125  return "No downward routes";
126  case RPL_MOP_NON_STORING:
127  return "Non-storing";
128  case RPL_MOP_STORING_NO_MULTICAST:
129  return "Storing";
130  case RPL_MOP_STORING_MULTICAST:
131  return "Storing+multicast";
132  default:
133  return "Unknown";
134  }
135 }
136 /*---------------------------------------------------------------------------*/
137 static const char *
138 rpl_ocp_to_str(int ocp)
139 {
140  switch(ocp) {
141  case RPL_OCP_OF0:
142  return "OF0";
143  case RPL_OCP_MRHOF:
144  return "MRHOF";
145  default:
146  return "Unknown";
147  }
148 }
149 /*---------------------------------------------------------------------------*/
150 static
151 PT_THREAD(cmd_rpl_nbr(struct pt *pt, shell_output_func output, char *args))
152 {
153  PT_BEGIN(pt);
154 
155  if(!curr_instance.used || rpl_neighbor_count() == 0) {
156  SHELL_OUTPUT(output, "RPL neighbors: none\n");
157  } else {
158  rpl_nbr_t *nbr = nbr_table_head(rpl_neighbors);
159  SHELL_OUTPUT(output, "RPL neighbors:\n");
160  while(nbr != NULL) {
161  char buf[120];
162  rpl_neighbor_snprint(buf, sizeof(buf), nbr);
163  SHELL_OUTPUT(output, "%s\n", buf);
164  nbr = nbr_table_next(rpl_neighbors, nbr);
165  }
166  }
167 
168  PT_END(pt);
169 }
170 /*---------------------------------------------------------------------------*/
171 static
172 PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args))
173 {
174  PT_BEGIN(pt);
175 
176  SHELL_OUTPUT(output, "RPL status:\n");
177  if(!curr_instance.used) {
178  SHELL_OUTPUT(output, "-- Instance: None\n");
179  } else {
180  SHELL_OUTPUT(output, "-- Instance: %u\n", curr_instance.instance_id);
181  if(NETSTACK_ROUTING.node_is_root()) {
182  SHELL_OUTPUT(output, "-- DAG root\n");
183  } else {
184  SHELL_OUTPUT(output, "-- DAG node\n");
185  }
186  SHELL_OUTPUT(output, "-- DAG: ");
187  shell_output_6addr(output, &curr_instance.dag.dag_id);
188  SHELL_OUTPUT(output, ", version %u\n", curr_instance.dag.version);
189  SHELL_OUTPUT(output, "-- Prefix: ");
190  shell_output_6addr(output, &curr_instance.dag.prefix_info.prefix);
191  SHELL_OUTPUT(output, "/%u\n", curr_instance.dag.prefix_info.length);
192  SHELL_OUTPUT(output, "-- MOP: %s\n", rpl_mop_to_str(curr_instance.mop));
193  SHELL_OUTPUT(output, "-- OF: %s\n", rpl_ocp_to_str(curr_instance.of->ocp));
194  SHELL_OUTPUT(output, "-- Hop rank increment: %u\n", curr_instance.min_hoprankinc);
195  SHELL_OUTPUT(output, "-- Default lifetime: %lu seconds\n", RPL_LIFETIME(curr_instance.default_lifetime));
196 
197  SHELL_OUTPUT(output, "-- State: %s\n", rpl_state_to_str(curr_instance.dag.state));
198  SHELL_OUTPUT(output, "-- Preferred parent: ");
199  if(curr_instance.dag.preferred_parent) {
200  shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
201  SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn);
202  } else {
203  SHELL_OUTPUT(output, "None\n");
204  }
205  SHELL_OUTPUT(output, "-- Rank: %u\n", curr_instance.dag.rank);
206  SHELL_OUTPUT(output, "-- Lowest rank: %u (%u)\n", curr_instance.dag.lowest_rank, curr_instance.max_rankinc);
207  SHELL_OUTPUT(output, "-- DTSN out: %u\n", curr_instance.dtsn_out);
208  SHELL_OUTPUT(output, "-- DAO sequence: last sent %u, last acked %u\n",
209  curr_instance.dag.dao_last_seqno, curr_instance.dag.dao_last_acked_seqno);
210  SHELL_OUTPUT(output, "-- Trickle timer: current %u, min %u, max %u, redundancy %u\n",
211  curr_instance.dag.dio_intcurrent, curr_instance.dio_intmin,
212  curr_instance.dio_intmin + curr_instance.dio_intdoubl, curr_instance.dio_redundancy);
213 
214  }
215 
216  PT_END(pt);
217 }
218 #endif /* ROUTING_CONF_RPL_LITE */
219 /*---------------------------------------------------------------------------*/
220 static void
221 echo_reply_handler(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data, uint16_t datalen)
222 {
223  if(curr_ping_output_func != NULL) {
224  curr_ping_output_func = NULL;
225  curr_ping_ttl = ttl;
226  curr_ping_datalen = datalen;
227  process_poll(curr_ping_process);
228  }
229 }
230 /*---------------------------------------------------------------------------*/
231 static
232 PT_THREAD(cmd_ping(struct pt *pt, shell_output_func output, char *args))
233 {
234  static uip_ipaddr_t remote_addr;
235  static struct etimer timeout_timer;
236  char *next_args;
237 
238  PT_BEGIN(pt);
239 
240  SHELL_ARGS_INIT(args, next_args);
241 
242  /* Get argument (remote IPv6) */
243  SHELL_ARGS_NEXT(args, next_args);
244  if(args == NULL) {
245  SHELL_OUTPUT(output, "Destination IPv6 address is not specified\n");
246  PT_EXIT(pt);
247  } else if(uiplib_ipaddrconv(args, &remote_addr) == 0) {
248  SHELL_OUTPUT(output, "Invalid IPv6 address: %s\n", args);
249  PT_EXIT(pt);
250  }
251 
252  SHELL_OUTPUT(output, "Pinging ");
253  shell_output_6addr(output, &remote_addr);
254  SHELL_OUTPUT(output, "\n");
255 
256  /* Send ping request */
257  curr_ping_process = PROCESS_CURRENT();
258  curr_ping_output_func = output;
259  etimer_set(&timeout_timer, PING_TIMEOUT);
260  uip_icmp6_send(&remote_addr, ICMP6_ECHO_REQUEST, 0, 4);
261  PT_WAIT_UNTIL(pt, curr_ping_output_func == NULL || etimer_expired(&timeout_timer));
262 
263  if(curr_ping_output_func != NULL) {
264  SHELL_OUTPUT(output, "Timeout\n");
265  curr_ping_output_func = NULL;
266  } else {
267  SHELL_OUTPUT(output, "Received ping reply from ");
268  shell_output_6addr(output, &remote_addr);
269  SHELL_OUTPUT(output, ", len %u, ttl %u, delay %lu ms\n",
270  curr_ping_datalen, curr_ping_ttl, (1000*(clock_time() - timeout_timer.timer.start))/CLOCK_SECOND);
271  }
272 
273  PT_END(pt);
274 }
275 /*---------------------------------------------------------------------------*/
276 static void
277 shell_output_log_levels(shell_output_func output)
278 {
279  int i = 0;
280  SHELL_OUTPUT(output, "Log levels:\n");
281  while(all_modules[i].name != NULL) {
282  SHELL_OUTPUT(output, "-- %-10s: %u (%s)\n",
283  all_modules[i].name,
284  *all_modules[i].curr_log_level,
285  log_level_to_str(*all_modules[i].curr_log_level));
286  i++;
287  }
288 }
289 /*---------------------------------------------------------------------------*/
290 static
291 PT_THREAD(cmd_log(struct pt *pt, shell_output_func output, char *args))
292 {
293  static int prev_level;
294  static int level;
295  char *next_args;
296  char *ptr;
297  char *module;
298 
299  PT_BEGIN(pt);
300 
301  SHELL_ARGS_INIT(args, next_args);
302 
303  /* Get and parse argument: module name */
304  SHELL_ARGS_NEXT(args, next_args);
305  module = args;
306  prev_level = log_get_level(module);
307  if(module == NULL || (strcmp("all", module) && prev_level == -1)) {
308  SHELL_OUTPUT(output, "Invalid first argument: %s\n", module)
309  shell_output_log_levels(output);
310  PT_EXIT(pt);
311  }
312 
313  /* Get and parse argument: log level */
314  SHELL_ARGS_NEXT(args, next_args);
315  if(args == NULL) {
316  level = -1;
317  } else {
318  level = (int)strtol(args, &ptr, 10);
319  }
320  if((level == 0 && args == ptr)
321  || level < LOG_LEVEL_NONE || level > LOG_LEVEL_DBG) {
322  SHELL_OUTPUT(output, "Invalid second argument: %s\n", args);
323  PT_EXIT(pt);
324  }
325 
326  /* Set log level */
327  if(level != prev_level) {
328  log_set_level(module, level);
329 #if MAC_CONF_WITH_TSCH && TSCH_LOG_PER_SLOT
330  if(!strcmp(module, "mac") || !strcmp(module, "all")) {
331  if(level >= LOG_LEVEL_DBG) {
332  tsch_log_init();
333  SHELL_OUTPUT(output, "TSCH logging started\n");
334  } else {
335  tsch_log_stop();
336  SHELL_OUTPUT(output, "TSCH logging stopped\n");
337  }
338  }
339 #endif /* MAC_CONF_WITH_TSCH && TSCH_LOG_PER_SLOT */
340  }
341 
342  shell_output_log_levels(output);
343 
344  PT_END(pt);
345 }
346 /*---------------------------------------------------------------------------*/
347 static
348 PT_THREAD(cmd_help(struct pt *pt, shell_output_func output, char *args))
349 {
350  struct shell_command_set_t *set;
351  const struct shell_command_t *cmd;
352  PT_BEGIN(pt);
353 
354  SHELL_OUTPUT(output, "Available commands:\n");
355  /* Note: we explicitly don't expend any code space to deal with shadowing */
356  for(set = list_head(shell_command_sets); set != NULL; set = list_item_next(set)) {
357  for(cmd = set->commands; cmd->name != NULL; ++cmd) {
358  SHELL_OUTPUT(output, "%s\n", cmd->help);
359  }
360  }
361 
362  PT_END(pt);
363 }
364 #if UIP_CONF_IPV6_RPL
365 /*---------------------------------------------------------------------------*/
366 static
367 PT_THREAD(cmd_rpl_set_root(struct pt *pt, shell_output_func output, char *args))
368 {
369  static int is_on;
370  static uip_ipaddr_t prefix;
371  char *next_args;
372 
373  PT_BEGIN(pt);
374 
375  SHELL_ARGS_INIT(args, next_args);
376 
377  /* Get first arg (0/1) */
378  SHELL_ARGS_NEXT(args, next_args);
379 
380  if(!strcmp(args, "1")) {
381  is_on = 1;
382  } else if(!strcmp(args, "0")) {
383  is_on = 0;
384  } else {
385  SHELL_OUTPUT(output, "Invalid argument: %s\n", args);
386  PT_EXIT(pt);
387  }
388 
389  /* Get first second arg (prefix) */
390  SHELL_ARGS_NEXT(args, next_args);
391  if(args != NULL) {
392  if(uiplib_ipaddrconv(args, &prefix) == 0) {
393  SHELL_OUTPUT(output, "Invalid Prefix: %s\n", args);
394  PT_EXIT(pt);
395  }
396  } else {
397  uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
398  }
399 
400  if(is_on) {
401  if(!NETSTACK_ROUTING.node_is_root()) {
402  SHELL_OUTPUT(output, "Setting as DAG root with prefix ");
403  shell_output_6addr(output, &prefix);
404  SHELL_OUTPUT(output, "/64\n");
405  NETSTACK_ROUTING.root_set_prefix(&prefix, NULL);
406  NETSTACK_ROUTING.root_start();
407  } else {
408  SHELL_OUTPUT(output, "Node is already a DAG root\n");
409  }
410  } else {
411  if(NETSTACK_ROUTING.node_is_root()) {
412  SHELL_OUTPUT(output, "Setting as non-root node: leaving DAG\n");
413  NETSTACK_ROUTING.leave_network();
414  } else {
415  SHELL_OUTPUT(output, "Node is not a DAG root\n");
416  }
417  }
418 
419  PT_END(pt);
420 }
421 /*---------------------------------------------------------------------------*/
422 static
423 PT_THREAD(cmd_rpl_global_repair(struct pt *pt, shell_output_func output, char *args))
424 {
425  PT_BEGIN(pt);
426 
427  SHELL_OUTPUT(output, "Triggering routing global repair\n")
428  NETSTACK_ROUTING.global_repair("Shell");
429 
430  PT_END(pt);
431 }
432 /*---------------------------------------------------------------------------*/
433 static
434 PT_THREAD(cmd_rpl_local_repair(struct pt *pt, shell_output_func output, char *args))
435 {
436  PT_BEGIN(pt);
437 
438  SHELL_OUTPUT(output, "Triggering routing local repair\n");
439  NETSTACK_ROUTING.local_repair("Shell");
440 
441  PT_END(pt);
442 }
443 /*---------------------------------------------------------------------------*/
444 #if ROUTING_CONF_RPL_LITE
445 static
446 PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char *args))
447 {
448  PT_BEGIN(pt);
449 
450  SHELL_OUTPUT(output, "Triggering routes refresh\n")
451  rpl_refresh_routes("Shell");
452 
453  PT_END(pt);
454 }
455 #endif /* ROUTING_CONF_RPL_LITE */
456 #endif /* UIP_CONF_IPV6_RPL */
457 /*---------------------------------------------------------------------------*/
458 static
459 PT_THREAD(cmd_ipaddr(struct pt *pt, shell_output_func output, char *args))
460 {
461  int i;
462  uint8_t state;
463 
464  PT_BEGIN(pt);
465 
466  SHELL_OUTPUT(output, "Node IPv6 addresses:\n");
467  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
468  state = uip_ds6_if.addr_list[i].state;
469  if(uip_ds6_if.addr_list[i].isused &&
470  (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
471  SHELL_OUTPUT(output, "-- ");
472  shell_output_6addr(output, &uip_ds6_if.addr_list[i].ipaddr);
473  SHELL_OUTPUT(output, "\n");
474  }
475  }
476 
477  PT_END(pt);
478 
479 }
480 /*---------------------------------------------------------------------------*/
481 static
482 PT_THREAD(cmd_ip_neighbors(struct pt *pt, shell_output_func output, char *args))
483 {
485 
486  PT_BEGIN(pt);
487 
488  nbr = uip_ds6_nbr_head();
489  if(nbr == NULL) {
490  SHELL_OUTPUT(output, "Node IPv6 neighbors: none\n");
491  PT_EXIT(pt);
492  }
493 
494  SHELL_OUTPUT(output, "Node IPv6 neighbors:\n");
495  while(nbr != NULL) {
496  SHELL_OUTPUT(output, "-- ");
497  shell_output_6addr(output, uip_ds6_nbr_get_ipaddr(nbr));
498  SHELL_OUTPUT(output, " <-> ");
499  shell_output_lladdr(output, (linkaddr_t *)uip_ds6_nbr_get_ll(nbr));
500  SHELL_OUTPUT(output, ", router %u, state %s ",
501  nbr->isrouter, ds6_nbr_state_to_str(nbr->state));
502  SHELL_OUTPUT(output, "\n");
503  nbr = uip_ds6_nbr_next(nbr);
504  }
505 
506  PT_END(pt);
507 
508 }
509 #if MAC_CONF_WITH_TSCH
510 /*---------------------------------------------------------------------------*/
511 static
512 PT_THREAD(cmd_tsch_set_coordinator(struct pt *pt, shell_output_func output, char *args))
513 {
514  static int is_on;
515  static int is_secured;
516  char *next_args;
517 
518  PT_BEGIN(pt);
519 
520  SHELL_ARGS_INIT(args, next_args);
521 
522  /* Get first arg (0/1) */
523  SHELL_ARGS_NEXT(args, next_args);
524 
525  if(!strcmp(args, "1")) {
526  is_on = 1;
527  } else if(!strcmp(args, "0")) {
528  is_on = 0;
529  } else {
530  SHELL_OUTPUT(output, "Invalid first argument: %s\n", args);
531  PT_EXIT(pt);
532  }
533 
534  /* Get first second arg (prefix) */
535  SHELL_ARGS_NEXT(args, next_args);
536  if(args != NULL) {
537  if(!strcmp(args, "1")) {
538 #if LLSEC802154_ENABLED
539  is_secured = 1;
540 #else /* LLSEC802154_ENABLED */
541  SHELL_OUTPUT(output, "Security is not compiled in.\n");
542  is_secured = 0;
543 #endif /* LLSEC802154_ENABLED */
544  } else if(!strcmp(args, "0")) {
545  is_secured = 0;
546  } else {
547  SHELL_OUTPUT(output, "Invalid second argument: %s\n", args);
548  PT_EXIT(pt);
549  }
550  } else {
551  is_secured = 0;
552  }
553 
554  SHELL_OUTPUT(output, "Setting as TSCH %s (%s)\n",
555  is_on ? "coordinator" : "non-coordinator", is_secured ? "secured" : "non-secured");
556 
557  tsch_set_pan_secured(is_secured);
558  tsch_set_coordinator(is_on);
559 
560  PT_END(pt);
561 }
562 /*---------------------------------------------------------------------------*/
563 static
564 PT_THREAD(cmd_tsch_status(struct pt *pt, shell_output_func output, char *args))
565 {
566  PT_BEGIN(pt);
567 
568  SHELL_OUTPUT(output, "TSCH status:\n");
569 
570  SHELL_OUTPUT(output, "-- Is coordinator: %u\n", tsch_is_coordinator);
571  SHELL_OUTPUT(output, "-- Is associated: %u\n", tsch_is_associated);
572  if(tsch_is_associated) {
574  SHELL_OUTPUT(output, "-- PAN ID: 0x%x\n", frame802154_get_pan_id());
575  SHELL_OUTPUT(output, "-- Is PAN secured: %u\n", tsch_is_pan_secured);
576  SHELL_OUTPUT(output, "-- Join priority: %u\n", tsch_join_priority);
577  SHELL_OUTPUT(output, "-- Time source: ");
578  if(n != NULL) {
579  shell_output_lladdr(output, &n->addr);
580  SHELL_OUTPUT(output, "\n");
581  } else {
582  SHELL_OUTPUT(output, "none\n");
583  }
584  SHELL_OUTPUT(output, "-- Last synchronized: %lu seconds ago\n", (clock_time() - last_sync_time) / CLOCK_SECOND);
585  SHELL_OUTPUT(output, "-- Drift w.r.t. coordinator: %ld ppm\n", tsch_adaptive_timesync_get_drift_ppm());
586  }
587 
588  PT_END(pt);
589 }
590 #endif /* MAC_CONF_WITH_TSCH */
591 /*---------------------------------------------------------------------------*/
592 static
593 PT_THREAD(cmd_routes(struct pt *pt, shell_output_func output, char *args))
594 {
595  uip_ds6_defrt_t *default_route;
596 
597  PT_BEGIN(pt);
598 
599  /* Our default route */
600  SHELL_OUTPUT(output, "Default route:\n");
601  default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose());
602  if(default_route != NULL) {
603  SHELL_OUTPUT(output, "-- ");
604  shell_output_6addr(output, &default_route->ipaddr);
605  if(default_route->lifetime.interval != 0) {
606  SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval);
607  } else {
608  SHELL_OUTPUT(output, " (lifetime: infinite)\n");
609  }
610  } else {
611  SHELL_OUTPUT(output, "-- None\n");
612  }
613 
614 #if UIP_CONF_IPV6_RPL
615  if(uip_sr_num_nodes() > 0) {
616  uip_sr_node_t *link;
617  /* Our routing links */
618  SHELL_OUTPUT(output, "Routing links (%u in total):\n", uip_sr_num_nodes());
619  link = uip_sr_node_head();
620  while(link != NULL) {
621  char buf[100];
622  uip_sr_link_snprint(buf, sizeof(buf), link);
623  SHELL_OUTPUT(output, "-- %s\n", buf);
624  link = uip_sr_node_next(link);
625  }
626  } else {
627  SHELL_OUTPUT(output, "No routing links\n");
628  }
629 #endif /* UIP_CONF_IPV6_RPL */
630 
631 #if (UIP_MAX_ROUTES != 0)
632  if(uip_ds6_route_num_routes() > 0) {
633  uip_ds6_route_t *route;
634  /* Our routing entries */
635  SHELL_OUTPUT(output, "Routing entries (%u in total):\n", uip_ds6_route_num_routes());
636  route = uip_ds6_route_head();
637  while(route != NULL) {
638  SHELL_OUTPUT(output, "-- ");
639  shell_output_6addr(output, &route->ipaddr);
640  SHELL_OUTPUT(output, " via ");
641  shell_output_6addr(output, uip_ds6_route_nexthop(route));
642  if((unsigned long)route->state.lifetime != 0xFFFFFFFF) {
643  SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime);
644  } else {
645  SHELL_OUTPUT(output, " (lifetime: infinite)\n");
646  }
647  route = uip_ds6_route_next(route);
648  }
649  } else {
650  SHELL_OUTPUT(output, "No routing entries\n");
651  }
652 #endif /* (UIP_MAX_ROUTES != 0) */
653 
654  PT_END(pt);
655 }
656 /*---------------------------------------------------------------------------*/
657 static
658 PT_THREAD(cmd_reboot(struct pt *pt, shell_output_func output, char *args))
659 {
660  PT_BEGIN(pt);
661  SHELL_OUTPUT(output, "rebooting\n");
662  watchdog_reboot();
663  PT_END(pt);
664 }
665 #if MAC_CONF_WITH_TSCH
666 /*---------------------------------------------------------------------------*/
667 static
668 PT_THREAD(cmd_tsch_schedule(struct pt *pt, shell_output_func output, char *args))
669 {
670  struct tsch_slotframe *sf;
671 
672  PT_BEGIN(pt);
673 
674  if(tsch_is_locked()) {
675  PT_EXIT(pt);
676  }
677 
679 
680  if(sf == NULL) {
681  SHELL_OUTPUT(output, "TSCH schedule: no slotframe\n");
682  } else {
683  SHELL_OUTPUT(output, "TSCH schedule:\n");
684  while(sf != NULL) {
685  struct tsch_link *l = list_head(sf->links_list);
686 
687  SHELL_OUTPUT(output, "-- Slotframe: handle %u, size %u, links:\n", sf->handle, sf->size.val);
688 
689  while(l != NULL) {
690  SHELL_OUTPUT(output, "---- Options %02x, type %u, timeslot %u, channel offset %u, address ",
691  l->link_options, l->link_type, l->timeslot, l->channel_offset);
692  shell_output_lladdr(output, &l->addr);
693  SHELL_OUTPUT(output, "\n");
694  l = list_item_next(l);
695  }
696 
698  }
699  }
700  PT_END(pt);
701 }
702 #endif /* MAC_CONF_WITH_TSCH */
703 /*---------------------------------------------------------------------------*/
704 #if TSCH_WITH_SIXTOP
705 void
706 shell_commands_set_6top_sub_cmd(shell_command_6top_sub_cmd_t sub_cmd)
707 {
708  sixtop_sub_cmd = sub_cmd;
709 }
710 /*---------------------------------------------------------------------------*/
711 static
712 PT_THREAD(cmd_6top(struct pt *pt, shell_output_func output, char *args))
713 {
714  char *next_args;
715 
716  PT_BEGIN(pt);
717 
718  SHELL_ARGS_INIT(args, next_args);
719 
720  if(sixtop_sub_cmd == NULL) {
721  SHELL_OUTPUT(output, "6top command is unavailable:\n");
722  } else {
723  SHELL_OUTPUT(output, "6top: ");
724  sixtop_sub_cmd(output, args);
725  }
726  SHELL_ARGS_NEXT(args, next_args);
727 
728  PT_END(pt);
729 }
730 #endif /* TSCH_WITH_SIXTOP */
731 /*---------------------------------------------------------------------------*/
732 void
734 {
735  list_init(shell_command_sets);
736  list_add(shell_command_sets, &builtin_shell_command_set);
737  /* Set up Ping Reply callback */
738  uip_icmp6_echo_reply_callback_add(&echo_reply_notification,
739  echo_reply_handler);
740 }
741 /*---------------------------------------------------------------------------*/
742 void
743 shell_command_set_register(struct shell_command_set_t *set)
744 {
745  list_push(shell_command_sets, set);
746 }
747 /*---------------------------------------------------------------------------*/
748 int
749 shell_command_set_deregister(struct shell_command_set_t *set)
750 {
751  if(!list_contains(shell_command_sets, set)) {
752  return !0;
753  }
754  list_remove(shell_command_sets, set);
755  return 0;
756 }
757 /*---------------------------------------------------------------------------*/
758 const struct shell_command_t *
759 shell_command_lookup(const char *name)
760 {
761  struct shell_command_set_t *set;
762  const struct shell_command_t *cmd;
763 
764  for(set = list_head(shell_command_sets);
765  set != NULL;
766  set = list_item_next(set)) {
767  for(cmd = set->commands; cmd->name != NULL; ++cmd) {
768  if(!strcmp(cmd->name, name)) {
769  return cmd;
770  }
771  }
772  }
773  return NULL;
774 }
775 /*---------------------------------------------------------------------------*/
776 const struct shell_command_t builtin_shell_commands[] = {
777  { "help", cmd_help, "'> help': Shows this help" },
778  { "reboot", cmd_reboot, "'> reboot': Reboot the board by watchdog_reboot()" },
779  { "ip-addr", cmd_ipaddr, "'> ip-addr': Shows all IPv6 addresses" },
780  { "ip-nbr", cmd_ip_neighbors, "'> ip-nbr': Shows all IPv6 neighbors" },
781  { "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." },
782  { "ping", cmd_ping, "'> ping addr': Pings the IPv6 address 'addr'" },
783 #if UIP_CONF_IPV6_RPL
784  { "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." },
785  { "rpl-local-repair", cmd_rpl_local_repair, "'> rpl-local-repair': Triggers a RPL local repair" },
786 #if ROUTING_CONF_RPL_LITE
787  { "rpl-refresh-routes", cmd_rpl_refresh_routes, "'> rpl-refresh-routes': Refreshes all routes through a DTSN increment" },
788 #endif /* ROUTING_CONF_RPL_LITE */
789  { "rpl-global-repair", cmd_rpl_global_repair, "'> rpl-global-repair': Triggers a RPL global repair" },
790 #endif /* UIP_CONF_IPV6_RPL */
791 #if ROUTING_CONF_RPL_LITE
792  { "rpl-status", cmd_rpl_status, "'> rpl-status': Shows a summary of the current RPL state" },
793  { "rpl-nbr", cmd_rpl_nbr, "'> rpl-nbr': Shows the RPL neighbor table" },
794 #endif /* ROUTING_CONF_RPL_LITE */
795  { "routes", cmd_routes, "'> routes': Shows the route entries" },
796 #if MAC_CONF_WITH_TSCH
797  { "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." },
798  { "tsch-schedule", cmd_tsch_schedule, "'> tsch-schedule': Shows the current TSCH schedule" },
799  { "tsch-status", cmd_tsch_status, "'> tsch-status': Shows a summary of the current TSCH state" },
800 #endif /* MAC_CONF_WITH_TSCH */
801 #if TSCH_WITH_SIXTOP
802  { "6top", cmd_6top, "'> 6top help': Shows 6top command usage" },
803 #endif /* TSCH_WITH_SIXTOP */
804  { NULL, NULL, NULL },
805 };
806 
807 static struct shell_command_set_t builtin_shell_command_set = {
808  .next = NULL,
809  .commands = builtin_shell_commands,
810 };
811 /** @} */
#define uip_ip6addr(addr, addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7)
Construct an IPv6 address from eight 16-bit words.
Definition: uip.h:961
An entry in the default router list.
Header file for ICMPv6 message and error handing (RFC 4443)
Main header file for the Contiki shell
uip_ipaddr_t * rpl_neighbor_get_ipaddr(rpl_nbr_t *nbr)
Returns a neighbor&#39;s (link-local) IPv6 address.
Definition: rpl-neighbor.c:249
void shell_commands_init(void)
Initializes Shell-commands module.
static uip_ds6_nbr_t * nbr
Pointer to llao option in uip_buf.
Definition: uip-nd6.c:115
struct tsch_slotframe * tsch_schedule_slotframe_next(struct tsch_slotframe *sf)
Access the next item in the list of slotframes.
int uip_sr_num_nodes(void)
Tells how many nodes are currently stored in the graph.
Definition: uip-sr.c:63
void list_push(list_t list, void *item)
Add an item to the start of the list.
Definition: list.c:164
void shell_output_lladdr(shell_output_func output, const linkaddr_t *lladdr)
Prints a link-layer address.
Definition: shell.c:65
void tsch_log_init(void)
Initialize log module.
watchdog_reboot()
Keeps control until the WDT throws a reset signal.
Definition: watchdog.c:94
bool list_contains(list_t list, void *item)
Check if the list contains an item.
Definition: list.c:338
TSCH neighbor information.
Definition: tsch-types.h:109
802.15.4e slotframe (contains links)
Definition: tsch-types.h:84
Main header file for the Contiki shell
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition: pt.h:114
struct tsch_neighbor * tsch_queue_get_time_source(void)
Get the TSCH time source (we currently assume there is only one)
Definition: tsch-queue.c:124
Common functionality of 802.15.4-compliant llsec_drivers.
#define PT_WAIT_UNTIL(pt, condition)
Block and wait until condition is true.
Definition: pt.h:147
#define RPL_LIFETIME(lifetime)
Compute lifetime, accounting for the lifetime unit.
Definition: rpl-types.h:72
#define ICMP6_ECHO_REQUEST
Echo request.
Definition: uip-icmp6.h:57
int(* root_start)(void)
Set the node as root and start a network.
Definition: routing.h:69
int rpl_neighbor_count(void)
Returns the number of nodes in the RPL neighbor table.
Definition: rpl-neighbor.c:168
static uint8_t output(const linkaddr_t *localdest)
Take an IP packet and format it to be sent on an 802.15.4 network using 6lowpan.
Definition: sicslowpan.c:1549
Header file for IPv6-related data structures.
void tsch_log_stop(void)
Stop logging module.
void(* root_set_prefix)(uip_ipaddr_t *prefix, uip_ipaddr_t *iid)
Set the prefix, for nodes that will operate as root.
Definition: routing.h:63
uip_sr_node_t * uip_sr_node_next(uip_sr_node_t *item)
Returns the next element of the non-storing node list.
Definition: uip-sr.c:200
#define PROCESS_CURRENT()
Get a pointer to the currently running process.
Definition: process.h:402
An entry in the routing table.
void log_set_level(const char *module, int level)
Sets a log level at run-time.
Definition: log.c:161
#define CLOCK_SECOND
A second, measured in system clock time.
Definition: clock.h:82
Header file for the IP address manipulation library.
void uip_icmp6_echo_reply_callback_add(struct uip_icmp6_echo_reply_notification *n, uip_icmp6_echo_reply_callback_t c)
Add a callback function for ping replies.
Definition: uip-icmp6.c:337
#define PT_END(pt)
Declare the end of a protothread.
Definition: pt.h:126
Linked list manipulation routines.
int(* node_is_root)(void)
Tells whether the node is a network root or not.
Definition: routing.h:75
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:82
uip_sr_node_t * uip_sr_node_head(void)
Returns the head of the non-storing node list.
Definition: uip-sr.c:194
rpl_dag_state
RPL DAG states.
Definition: rpl-types.h:177
Routing driver header file
All information related to a RPL neighbor.
Definition: rpl-types.h:136
Main API declarations for TSCH.
clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:118
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:213
int tsch_is_locked(void)
Checks if the TSCH lock is set.
struct tsch_slotframe * tsch_schedule_slotframe_head(void)
Access the first item in the list of slotframes.
long int tsch_adaptive_timesync_get_drift_ppm(void)
Gives the estimated clock drift w.r.t.
#define PT_EXIT(pt)
Exit the protothread.
Definition: pt.h:245
#define ADDR_TENTATIVE
Possible states for the an address (RFC 4862)
Definition: uip-ds6.h:155
#define PT_THREAD(name_args)
Declaration of a protothread.
Definition: pt.h:99
#define NBR_INCOMPLETE
Possible states for the nbr cache entries.
Definition: uip-ds6-nbr.h:60
void(* leave_network)(void)
Leave the network the node is part of.
Definition: routing.h:95
A timer.
Definition: etimer.h:75
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:142
void list_init(list_t list)
Initialize a list.
Definition: list.c:65
int uip_sr_link_snprint(char *buf, int buflen, uip_sr_node_t *link)
Print a textual description of a source routing link.
Definition: uip-sr.c:252
Header file for the uIP TCP/IP stack.
const char * log_level_to_str(int level)
Returns a textual description of a log level.
Definition: log.c:192
int log_get_level(const char *module)
Returns the current log level.
Definition: log.c:176
#define LIST(name)
Declare a linked list.
Definition: list.h:88
uip_ds6_netif_t uip_ds6_if
The single interface.
Definition: uip-ds6.c:75
void rpl_refresh_routes(const char *str)
Triggers a route fresh via DTSN increment.
Definition: rpl-dag.c:189
void(* local_repair)(const char *str)
Triggers a RPL local topology repair.
Definition: routing.h:119
void tsch_set_pan_secured(int enable)
Enable/disable security.
Definition: tsch.c:178
void uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
Send an icmpv6 message.
Definition: uip-icmp6.c:254
#define uiplib_ipaddrconv
Convert a textual representation of an IP address to a numerical representation.
Definition: uiplib.h:72
Header file for the logging system
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
void list_remove(list_t list, void *item)
Remove a specific element from a list.
Definition: list.c:237
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:322
int rpl_neighbor_snprint(char *buf, int buflen, rpl_nbr_t *nbr)
Print a textual description of RPL neighbor into a string.
Definition: rpl-neighbor.c:90
A node in a source routing graph, stored at the root and representing all child-parent relationship...
Definition: uip-sr.h:92
void tsch_set_coordinator(int enable)
Set the node as PAN coordinator.
Definition: tsch.c:168
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:69