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 "sys/log.h"
49 #include "dev/watchdog.h"
50 #include "net/ipv6/uip.h"
51 #include "net/ipv6/uiplib.h"
52 #include "net/ipv6/uip-icmp6.h"
53 #include "net/ipv6/uip-ds6.h"
54 #if MAC_CONF_WITH_TSCH
55 #include "net/mac/tsch/tsch.h"
56 #endif /* MAC_CONF_WITH_TSCH */
57 #include "net/routing/routing.h"
58 #include "net/mac/llsec802154.h"
59 
60 /* For RPL-specific commands */
61 #if ROUTING_CONF_RPL_LITE
62 #include "net/routing/rpl-lite/rpl.h"
63 #elif ROUTING_CONF_RPL_CLASSIC
64 #include "net/routing/rpl-classic/rpl.h"
65 #endif
66 
67 #include <stdlib.h>
68 
69 #define PING_TIMEOUT (5 * CLOCK_SECOND)
70 
71 static struct uip_icmp6_echo_reply_notification echo_reply_notification;
72 static shell_output_func *curr_ping_output_func = NULL;
73 static struct process *curr_ping_process;
74 static uint8_t curr_ping_ttl;
75 static uint16_t curr_ping_datalen;
76 #if TSCH_WITH_SIXTOP
77 static shell_command_6top_sub_cmd_t sixtop_sub_cmd = NULL;
78 #endif /* TSCH_WITH_SIXTOP */
79 
80 /*---------------------------------------------------------------------------*/
81 static const char *
82 ds6_nbr_state_to_str(uint8_t state)
83 {
84  switch(state) {
85  case NBR_INCOMPLETE:
86  return "Incomplete";
87  case NBR_REACHABLE:
88  return "Reachable";
89  case NBR_STALE:
90  return "Stale";
91  case NBR_DELAY:
92  return "Delay";
93  case NBR_PROBE:
94  return "Probe";
95  default:
96  return "Unknown";
97  }
98 }
99 #if ROUTING_CONF_RPL_LITE
100 /*---------------------------------------------------------------------------*/
101 static const char *
102 rpl_state_to_str(enum rpl_dag_state state)
103 {
104  switch(state) {
105  case DAG_INITIALIZED:
106  return "Initialized";
107  case DAG_JOINED:
108  return "Joined";
109  case DAG_REACHABLE:
110  return "Reachable";
111  case DAG_POISONING:
112  return "Poisoning";
113  default:
114  return "Unknown";
115  }
116 }
117 /*---------------------------------------------------------------------------*/
118 static const char *
119 rpl_mop_to_str(int mop)
120 {
121  switch(mop) {
122  case RPL_MOP_NO_DOWNWARD_ROUTES:
123  return "No downward routes";
124  case RPL_MOP_NON_STORING:
125  return "Non-storing";
126  case RPL_MOP_STORING_NO_MULTICAST:
127  return "Storing";
128  case RPL_MOP_STORING_MULTICAST:
129  return "Storing+multicast";
130  default:
131  return "Unknown";
132  }
133 }
134 /*---------------------------------------------------------------------------*/
135 static const char *
136 rpl_ocp_to_str(int ocp)
137 {
138  switch(ocp) {
139  case RPL_OCP_OF0:
140  return "OF0";
141  case RPL_OCP_MRHOF:
142  return "MRHOF";
143  default:
144  return "Unknown";
145  }
146 }
147 /*---------------------------------------------------------------------------*/
148 static
149 PT_THREAD(cmd_rpl_nbr(struct pt *pt, shell_output_func output, char *args))
150 {
151  PT_BEGIN(pt);
152 
153  if(!curr_instance.used || rpl_neighbor_count() == 0) {
154  SHELL_OUTPUT(output, "RPL neighbors: none\n");
155  } else {
156  rpl_nbr_t *nbr = nbr_table_head(rpl_neighbors);
157  SHELL_OUTPUT(output, "RPL neighbors:\n");
158  while(nbr != NULL) {
159  char buf[120];
160  rpl_neighbor_snprint(buf, sizeof(buf), nbr);
161  SHELL_OUTPUT(output, "%s\n", buf);
162  nbr = nbr_table_next(rpl_neighbors, nbr);
163  }
164  }
165 
166  PT_END(pt);
167 }
168 /*---------------------------------------------------------------------------*/
169 static
170 PT_THREAD(cmd_rpl_status(struct pt *pt, shell_output_func output, char *args))
171 {
172  PT_BEGIN(pt);
173 
174  SHELL_OUTPUT(output, "RPL status:\n");
175  if(!curr_instance.used) {
176  SHELL_OUTPUT(output, "-- Instance: None\n");
177  } else {
178  SHELL_OUTPUT(output, "-- Instance: %u\n", curr_instance.instance_id);
179  if(NETSTACK_ROUTING.node_is_root()) {
180  SHELL_OUTPUT(output, "-- DAG root\n");
181  } else {
182  SHELL_OUTPUT(output, "-- DAG node\n");
183  }
184  SHELL_OUTPUT(output, "-- DAG: ");
185  shell_output_6addr(output, &curr_instance.dag.dag_id);
186  SHELL_OUTPUT(output, ", version %u\n", curr_instance.dag.version);
187  SHELL_OUTPUT(output, "-- Prefix: ");
188  shell_output_6addr(output, &curr_instance.dag.prefix_info.prefix);
189  SHELL_OUTPUT(output, "/%u\n", curr_instance.dag.prefix_info.length);
190  SHELL_OUTPUT(output, "-- MOP: %s\n", rpl_mop_to_str(curr_instance.mop));
191  SHELL_OUTPUT(output, "-- OF: %s\n", rpl_ocp_to_str(curr_instance.of->ocp));
192  SHELL_OUTPUT(output, "-- Hop rank increment: %u\n", curr_instance.min_hoprankinc);
193  SHELL_OUTPUT(output, "-- Default lifetime: %lu seconds\n", RPL_LIFETIME(curr_instance.default_lifetime));
194 
195  SHELL_OUTPUT(output, "-- State: %s\n", rpl_state_to_str(curr_instance.dag.state));
196  SHELL_OUTPUT(output, "-- Preferred parent: ");
197  if(curr_instance.dag.preferred_parent) {
198  shell_output_6addr(output, rpl_neighbor_get_ipaddr(curr_instance.dag.preferred_parent));
199  SHELL_OUTPUT(output, " (last DTSN: %u)\n", curr_instance.dag.preferred_parent->dtsn);
200  } else {
201  SHELL_OUTPUT(output, "None\n");
202  }
203  SHELL_OUTPUT(output, "-- Rank: %u\n", curr_instance.dag.rank);
204  SHELL_OUTPUT(output, "-- Lowest rank: %u (%u)\n", curr_instance.dag.lowest_rank, curr_instance.max_rankinc);
205  SHELL_OUTPUT(output, "-- DTSN out: %u\n", curr_instance.dtsn_out);
206  SHELL_OUTPUT(output, "-- DAO sequence: last sent %u, last acked %u\n",
207  curr_instance.dag.dao_last_seqno, curr_instance.dag.dao_last_acked_seqno);
208  SHELL_OUTPUT(output, "-- Trickle timer: current %u, min %u, max %u, redundancy %u\n",
209  curr_instance.dag.dio_intcurrent, curr_instance.dio_intmin,
210  curr_instance.dio_intmin + curr_instance.dio_intdoubl, curr_instance.dio_redundancy);
211 
212  }
213 
214  PT_END(pt);
215 }
216 #endif /* ROUTING_CONF_RPL_LITE */
217 /*---------------------------------------------------------------------------*/
218 static void
219 echo_reply_handler(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data, uint16_t datalen)
220 {
221  if(curr_ping_output_func != NULL) {
222  curr_ping_output_func = NULL;
223  curr_ping_ttl = ttl;
224  curr_ping_datalen = datalen;
225  process_poll(curr_ping_process);
226  }
227 }
228 /*---------------------------------------------------------------------------*/
229 static
230 PT_THREAD(cmd_ping(struct pt *pt, shell_output_func output, char *args))
231 {
232  static uip_ipaddr_t remote_addr;
233  static struct etimer timeout_timer;
234  char *next_args;
235 
236  PT_BEGIN(pt);
237 
238  SHELL_ARGS_INIT(args, next_args);
239 
240  /* Get argument (remote IPv6) */
241  SHELL_ARGS_NEXT(args, next_args);
242  if(args == NULL) {
243  SHELL_OUTPUT(output, "Destination IPv6 address is not specified\n");
244  PT_EXIT(pt);
245  } else if(uiplib_ipaddrconv(args, &remote_addr) == 0) {
246  SHELL_OUTPUT(output, "Invalid IPv6 address: %s\n", args);
247  PT_EXIT(pt);
248  }
249 
250  SHELL_OUTPUT(output, "Pinging ");
251  shell_output_6addr(output, &remote_addr);
252  SHELL_OUTPUT(output, "\n");
253 
254  /* Send ping request */
255  curr_ping_process = PROCESS_CURRENT();
256  curr_ping_output_func = output;
257  etimer_set(&timeout_timer, PING_TIMEOUT);
258  uip_icmp6_send(&remote_addr, ICMP6_ECHO_REQUEST, 0, 4);
259  PT_WAIT_UNTIL(pt, curr_ping_output_func == NULL || etimer_expired(&timeout_timer));
260 
261  if(curr_ping_output_func != NULL) {
262  SHELL_OUTPUT(output, "Timeout\n");
263  curr_ping_output_func = NULL;
264  } else {
265  SHELL_OUTPUT(output, "Received ping reply from ");
266  shell_output_6addr(output, &remote_addr);
267  SHELL_OUTPUT(output, ", len %u, ttl %u, delay %lu ms\n",
268  curr_ping_datalen, curr_ping_ttl, (1000*(clock_time() - timeout_timer.timer.start))/CLOCK_SECOND);
269  }
270 
271  PT_END(pt);
272 }
273 /*---------------------------------------------------------------------------*/
274 static void
275 shell_output_log_levels(shell_output_func output)
276 {
277  int i = 0;
278  SHELL_OUTPUT(output, "Log levels:\n");
279  while(all_modules[i].name != NULL) {
280  SHELL_OUTPUT(output, "-- %-10s: %u (%s)\n",
281  all_modules[i].name,
282  *all_modules[i].curr_log_level,
283  log_level_to_str(*all_modules[i].curr_log_level));
284  i++;
285  }
286 }
287 /*---------------------------------------------------------------------------*/
288 static
289 PT_THREAD(cmd_log(struct pt *pt, shell_output_func output, char *args))
290 {
291  static int prev_level;
292  static int level;
293  char *next_args;
294  char *ptr;
295  char *module;
296 
297  PT_BEGIN(pt);
298 
299  SHELL_ARGS_INIT(args, next_args);
300 
301  /* Get and parse argument: module name */
302  SHELL_ARGS_NEXT(args, next_args);
303  module = args;
304  prev_level = log_get_level(module);
305  if(module == NULL || (strcmp("all", module) && prev_level == -1)) {
306  SHELL_OUTPUT(output, "Invalid first argument: %s\n", module)
307  shell_output_log_levels(output);
308  PT_EXIT(pt);
309  }
310 
311  /* Get and parse argument: log level */
312  SHELL_ARGS_NEXT(args, next_args);
313  if(args == NULL) {
314  level = -1;
315  } else {
316  level = (int)strtol(args, &ptr, 10);
317  }
318  if((level == 0 && args == ptr)
319  || level < LOG_LEVEL_NONE || level > LOG_LEVEL_DBG) {
320  SHELL_OUTPUT(output, "Invalid second argument: %s\n", args);
321  PT_EXIT(pt);
322  }
323 
324  /* Set log level */
325  if(level != prev_level) {
326  log_set_level(module, level);
327 #if MAC_CONF_WITH_TSCH && TSCH_LOG_PER_SLOT
328  if(!strcmp(module, "mac") || !strcmp(module, "all")) {
329  if(level >= LOG_LEVEL_DBG) {
330  tsch_log_init();
331  SHELL_OUTPUT(output, "TSCH logging started\n");
332  } else {
333  tsch_log_stop();
334  SHELL_OUTPUT(output, "TSCH logging stopped\n");
335  }
336  }
337 #endif /* MAC_CONF_WITH_TSCH && TSCH_LOG_PER_SLOT */
338  }
339 
340  shell_output_log_levels(output);
341 
342  PT_END(pt);
343 }
344 /*---------------------------------------------------------------------------*/
345 static
346 PT_THREAD(cmd_help(struct pt *pt, shell_output_func output, char *args))
347 {
348  struct shell_command_t *cmd_ptr;
349 
350  PT_BEGIN(pt);
351 
352  SHELL_OUTPUT(output, "Available commands:\n");
353  cmd_ptr = shell_commands;
354  while(cmd_ptr->name != NULL) {
355  SHELL_OUTPUT(output, "%s\n", cmd_ptr->help);
356  cmd_ptr++;
357  }
358 
359  PT_END(pt);
360 }
361 #if UIP_CONF_IPV6_RPL
362 /*---------------------------------------------------------------------------*/
363 static
364 PT_THREAD(cmd_rpl_set_root(struct pt *pt, shell_output_func output, char *args))
365 {
366  static int is_on;
367  static uip_ipaddr_t prefix;
368  char *next_args;
369 
370  PT_BEGIN(pt);
371 
372  SHELL_ARGS_INIT(args, next_args);
373 
374  /* Get first arg (0/1) */
375  SHELL_ARGS_NEXT(args, next_args);
376 
377  if(!strcmp(args, "1")) {
378  is_on = 1;
379  } else if(!strcmp(args, "0")) {
380  is_on = 0;
381  } else {
382  SHELL_OUTPUT(output, "Invalid argument: %s\n", args);
383  PT_EXIT(pt);
384  }
385 
386  /* Get first second arg (prefix) */
387  SHELL_ARGS_NEXT(args, next_args);
388  if(args != NULL) {
389  if(uiplib_ipaddrconv(args, &prefix) == 0) {
390  SHELL_OUTPUT(output, "Invalid Prefix: %s\n", args);
391  PT_EXIT(pt);
392  }
393  } else {
394  uip_ip6addr(&prefix, UIP_DS6_DEFAULT_PREFIX, 0, 0, 0, 0, 0, 0, 0);
395  }
396 
397  if(is_on) {
398  if(!NETSTACK_ROUTING.node_is_root()) {
399  SHELL_OUTPUT(output, "Setting as DAG root with prefix ");
400  shell_output_6addr(output, &prefix);
401  SHELL_OUTPUT(output, "/64\n");
402  NETSTACK_ROUTING.root_set_prefix(&prefix, NULL);
403  NETSTACK_ROUTING.root_start();
404  } else {
405  SHELL_OUTPUT(output, "Node is already a DAG root\n");
406  }
407  } else {
408  if(NETSTACK_ROUTING.node_is_root()) {
409  SHELL_OUTPUT(output, "Setting as non-root node: leaving DAG\n");
410  NETSTACK_ROUTING.leave_network();
411  } else {
412  SHELL_OUTPUT(output, "Node is not a DAG root\n");
413  }
414  }
415 
416  PT_END(pt);
417 }
418 /*---------------------------------------------------------------------------*/
419 static
420 PT_THREAD(cmd_rpl_global_repair(struct pt *pt, shell_output_func output, char *args))
421 {
422  PT_BEGIN(pt);
423 
424  SHELL_OUTPUT(output, "Triggering routing global repair\n")
425  NETSTACK_ROUTING.global_repair("Shell");
426 
427  PT_END(pt);
428 }
429 /*---------------------------------------------------------------------------*/
430 static
431 PT_THREAD(cmd_rpl_local_repair(struct pt *pt, shell_output_func output, char *args))
432 {
433  PT_BEGIN(pt);
434 
435  SHELL_OUTPUT(output, "Triggering routing local repair\n");
436  NETSTACK_ROUTING.local_repair("Shell");
437 
438  PT_END(pt);
439 }
440 /*---------------------------------------------------------------------------*/
441 #if ROUTING_CONF_RPL_LITE
442 static
443 PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char *args))
444 {
445  PT_BEGIN(pt);
446 
447  SHELL_OUTPUT(output, "Triggering routes refresh\n")
448  rpl_refresh_routes("Shell");
449 
450  PT_END(pt);
451 }
452 #endif /* ROUTING_CONF_RPL_LITE */
453 #endif /* UIP_CONF_IPV6_RPL */
454 /*---------------------------------------------------------------------------*/
455 static
456 PT_THREAD(cmd_ipaddr(struct pt *pt, shell_output_func output, char *args))
457 {
458  int i;
459  uint8_t state;
460 
461  PT_BEGIN(pt);
462 
463  SHELL_OUTPUT(output, "Node IPv6 addresses:\n");
464  for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
465  state = uip_ds6_if.addr_list[i].state;
466  if(uip_ds6_if.addr_list[i].isused &&
467  (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
468  SHELL_OUTPUT(output, "-- ");
469  shell_output_6addr(output, &uip_ds6_if.addr_list[i].ipaddr);
470  SHELL_OUTPUT(output, "\n");
471  }
472  }
473 
474  PT_END(pt);
475 
476 }
477 /*---------------------------------------------------------------------------*/
478 static
479 PT_THREAD(cmd_ip_neighbors(struct pt *pt, shell_output_func output, char *args))
480 {
482 
483  PT_BEGIN(pt);
484 
485  nbr = uip_ds6_nbr_head();
486  if(nbr == NULL) {
487  SHELL_OUTPUT(output, "Node IPv6 neighbors: none\n");
488  PT_EXIT(pt);
489  }
490 
491  SHELL_OUTPUT(output, "Node IPv6 neighbors:\n");
492  while(nbr != NULL) {
493  SHELL_OUTPUT(output, "-- ");
494  shell_output_6addr(output, uip_ds6_nbr_get_ipaddr(nbr));
495  SHELL_OUTPUT(output, " <-> ");
496  shell_output_lladdr(output, (linkaddr_t *)uip_ds6_nbr_get_ll(nbr));
497  SHELL_OUTPUT(output, ", router %u, state %s ",
498  nbr->isrouter, ds6_nbr_state_to_str(nbr->state));
499  SHELL_OUTPUT(output, "\n");
500  nbr = uip_ds6_nbr_next(nbr);
501  }
502 
503  PT_END(pt);
504 
505 }
506 #if MAC_CONF_WITH_TSCH
507 /*---------------------------------------------------------------------------*/
508 static
509 PT_THREAD(cmd_tsch_set_coordinator(struct pt *pt, shell_output_func output, char *args))
510 {
511  static int is_on;
512  static int is_secured;
513  char *next_args;
514 
515  PT_BEGIN(pt);
516 
517  SHELL_ARGS_INIT(args, next_args);
518 
519  /* Get first arg (0/1) */
520  SHELL_ARGS_NEXT(args, next_args);
521 
522  if(!strcmp(args, "1")) {
523  is_on = 1;
524  } else if(!strcmp(args, "0")) {
525  is_on = 0;
526  } else {
527  SHELL_OUTPUT(output, "Invalid first argument: %s\n", args);
528  PT_EXIT(pt);
529  }
530 
531  /* Get first second arg (prefix) */
532  SHELL_ARGS_NEXT(args, next_args);
533  if(args != NULL) {
534  if(!strcmp(args, "1")) {
535 #if LLSEC802154_ENABLED
536  is_secured = 1;
537 #else /* LLSEC802154_ENABLED */
538  SHELL_OUTPUT(output, "Security is not compiled in.\n");
539  is_secured = 0;
540 #endif /* LLSEC802154_ENABLED */
541  } else if(!strcmp(args, "0")) {
542  is_secured = 0;
543  } else {
544  SHELL_OUTPUT(output, "Invalid second argument: %s\n", args);
545  PT_EXIT(pt);
546  }
547  } else {
548  is_secured = 0;
549  }
550 
551  SHELL_OUTPUT(output, "Setting as TSCH %s (%s)\n",
552  is_on ? "coordinator" : "non-coordinator", is_secured ? "secured" : "non-secured");
553 
554  tsch_set_pan_secured(is_secured);
555  tsch_set_coordinator(is_on);
556 
557  PT_END(pt);
558 }
559 /*---------------------------------------------------------------------------*/
560 static
561 PT_THREAD(cmd_tsch_status(struct pt *pt, shell_output_func output, char *args))
562 {
563  PT_BEGIN(pt);
564 
565  SHELL_OUTPUT(output, "TSCH status:\n");
566 
567  SHELL_OUTPUT(output, "-- Is coordinator: %u\n", tsch_is_coordinator);
568  SHELL_OUTPUT(output, "-- Is associated: %u\n", tsch_is_associated);
569  if(tsch_is_associated) {
571  SHELL_OUTPUT(output, "-- PAN ID: 0x%x\n", frame802154_get_pan_id());
572  SHELL_OUTPUT(output, "-- Is PAN secured: %u\n", tsch_is_pan_secured);
573  SHELL_OUTPUT(output, "-- Join priority: %u\n", tsch_join_priority);
574  SHELL_OUTPUT(output, "-- Time source: ");
575  if(n != NULL) {
576  shell_output_lladdr(output, &n->addr);
577  SHELL_OUTPUT(output, "\n");
578  } else {
579  SHELL_OUTPUT(output, "none\n");
580  }
581  SHELL_OUTPUT(output, "-- Last synchronized: %lu seconds ago\n", (clock_time() - last_sync_time) / CLOCK_SECOND);
582  SHELL_OUTPUT(output, "-- Drift w.r.t. coordinator: %ld ppm\n", tsch_adaptive_timesync_get_drift_ppm());
583  }
584 
585  PT_END(pt);
586 }
587 #endif /* MAC_CONF_WITH_TSCH */
588 /*---------------------------------------------------------------------------*/
589 static
590 PT_THREAD(cmd_routes(struct pt *pt, shell_output_func output, char *args))
591 {
592  uip_ds6_defrt_t *default_route;
593 
594  PT_BEGIN(pt);
595 
596  /* Our default route */
597  SHELL_OUTPUT(output, "Default route:\n");
598  default_route = uip_ds6_defrt_lookup(uip_ds6_defrt_choose());
599  if(default_route != NULL) {
600  SHELL_OUTPUT(output, "-- ");
601  shell_output_6addr(output, &default_route->ipaddr);
602  if(default_route->lifetime.interval != 0) {
603  SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)default_route->lifetime.interval);
604  } else {
605  SHELL_OUTPUT(output, " (lifetime: infinite)\n");
606  }
607  } else {
608  SHELL_OUTPUT(output, "-- None\n");
609  }
610 
611 #if UIP_CONF_IPV6_RPL
612  if(uip_sr_num_nodes() > 0) {
613  uip_sr_node_t *link;
614  /* Our routing links */
615  SHELL_OUTPUT(output, "Routing links (%u in total):\n", uip_sr_num_nodes());
616  link = uip_sr_node_head();
617  while(link != NULL) {
618  char buf[100];
619  uip_sr_link_snprint(buf, sizeof(buf), link);
620  SHELL_OUTPUT(output, "-- %s\n", buf);
621  link = uip_sr_node_next(link);
622  }
623  } else {
624  SHELL_OUTPUT(output, "No routing links\n");
625  }
626 #endif /* UIP_CONF_IPV6_RPL */
627 
628 #if (UIP_MAX_ROUTES != 0)
629  if(uip_ds6_route_num_routes() > 0) {
630  uip_ds6_route_t *route;
631  /* Our routing entries */
632  SHELL_OUTPUT(output, "Routing entries (%u in total):\n", uip_ds6_route_num_routes());
633  route = uip_ds6_route_head();
634  while(route != NULL) {
635  SHELL_OUTPUT(output, "-- ");
636  shell_output_6addr(output, &route->ipaddr);
637  SHELL_OUTPUT(output, " via ");
638  shell_output_6addr(output, uip_ds6_route_nexthop(route));
639  if((unsigned long)route->state.lifetime != 0xFFFFFFFF) {
640  SHELL_OUTPUT(output, " (lifetime: %lu seconds)\n", (unsigned long)route->state.lifetime);
641  } else {
642  SHELL_OUTPUT(output, " (lifetime: infinite)\n");
643  }
644  route = uip_ds6_route_next(route);
645  }
646  } else {
647  SHELL_OUTPUT(output, "No routing entries\n");
648  }
649 #endif /* (UIP_MAX_ROUTES != 0) */
650 
651  PT_END(pt);
652 }
653 /*---------------------------------------------------------------------------*/
654 static
655 PT_THREAD(cmd_reboot(struct pt *pt, shell_output_func output, char *args))
656 {
657  PT_BEGIN(pt);
658  SHELL_OUTPUT(output, "rebooting\n");
659  watchdog_reboot();
660  PT_END(pt);
661 }
662 #if MAC_CONF_WITH_TSCH
663 /*---------------------------------------------------------------------------*/
664 static
665 PT_THREAD(cmd_tsch_schedule(struct pt *pt, shell_output_func output, char *args))
666 {
667  struct tsch_slotframe *sf;
668 
669  PT_BEGIN(pt);
670 
671  if(tsch_is_locked()) {
672  PT_EXIT(pt);
673  }
674 
676 
677  if(sf == NULL) {
678  SHELL_OUTPUT(output, "TSCH schedule: no slotframe\n");
679  } else {
680  SHELL_OUTPUT(output, "TSCH schedule:\n");
681  while(sf != NULL) {
682  struct tsch_link *l = list_head(sf->links_list);
683 
684  SHELL_OUTPUT(output, "-- Slotframe: handle %u, size %u, links:\n", sf->handle, sf->size.val);
685 
686  while(l != NULL) {
687  SHELL_OUTPUT(output, "---- Options %02x, type %u, timeslot %u, channel offset %u, address ",
688  l->link_options, l->link_type, l->timeslot, l->channel_offset);
689  shell_output_lladdr(output, &l->addr);
690  SHELL_OUTPUT(output, "\n");
691  l = list_item_next(l);
692  }
693 
695  }
696  }
697  PT_END(pt);
698 }
699 #endif /* MAC_CONF_WITH_TSCH */
700 /*---------------------------------------------------------------------------*/
701 #if TSCH_WITH_SIXTOP
702 void
703 shell_commands_set_6top_sub_cmd(shell_command_6top_sub_cmd_t sub_cmd)
704 {
705  sixtop_sub_cmd = sub_cmd;
706 }
707 /*---------------------------------------------------------------------------*/
708 static
709 PT_THREAD(cmd_6top(struct pt *pt, shell_output_func output, char *args))
710 {
711  char *next_args;
712 
713  PT_BEGIN(pt);
714 
715  SHELL_ARGS_INIT(args, next_args);
716 
717  if(sixtop_sub_cmd == NULL) {
718  SHELL_OUTPUT(output, "6top command is unavailable:\n");
719  } else {
720  SHELL_OUTPUT(output, "6top: ");
721  sixtop_sub_cmd(output, args);
722  }
723  SHELL_ARGS_NEXT(args, next_args);
724 
725  PT_END(pt);
726 }
727 #endif /* TSCH_WITH_SIXTOP */
728 /*---------------------------------------------------------------------------*/
729 void
731 {
732  /* Set up Ping Reply callback */
733  uip_icmp6_echo_reply_callback_add(&echo_reply_notification,
734  echo_reply_handler);
735 }
736 /*---------------------------------------------------------------------------*/
737 struct shell_command_t shell_commands[] = {
738  { "help", cmd_help, "'> help': Shows this help" },
739  { "reboot", cmd_reboot, "'> reboot': Reboot the board by watchdog_reboot()" },
740  { "ip-addr", cmd_ipaddr, "'> ip-addr': Shows all IPv6 addresses" },
741  { "ip-nbr", cmd_ip_neighbors, "'> ip-nbr': Shows all IPv6 neighbors" },
742  { "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." },
743  { "ping", cmd_ping, "'> ping addr': Pings the IPv6 address 'addr'" },
744 #if UIP_CONF_IPV6_RPL
745  { "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." },
746  { "rpl-local-repair", cmd_rpl_local_repair, "'> rpl-local-repair': Triggers a RPL local repair" },
747 #if ROUTING_CONF_RPL_LITE
748  { "rpl-refresh-routes", cmd_rpl_refresh_routes, "'> rpl-refresh-routes': Refreshes all routes through a DTSN increment" },
749 #endif /* ROUTING_CONF_RPL_LITE */
750  { "rpl-global-repair", cmd_rpl_global_repair, "'> rpl-global-repair': Triggers a RPL global repair" },
751 #endif /* UIP_CONF_IPV6_RPL */
752 #if ROUTING_CONF_RPL_LITE
753  { "rpl-status", cmd_rpl_status, "'> rpl-status': Shows a summary of the current RPL state" },
754  { "rpl-nbr", cmd_rpl_nbr, "'> rpl-nbr': Shows the RPL neighbor table" },
755 #endif /* ROUTING_CONF_RPL_LITE */
756  { "routes", cmd_routes, "'> routes': Shows the route entries" },
757 #if MAC_CONF_WITH_TSCH
758  { "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." },
759  { "tsch-schedule", cmd_tsch_schedule, "'> tsch-schedule': Shows the current TSCH schedule" },
760  { "tsch-status", cmd_tsch_status, "'> tsch-status': Shows a summary of the current TSCH state" },
761 #endif /* MAC_CONF_WITH_TSCH */
762 #if TSCH_WITH_SIXTOP
763  { "6top", cmd_6top, "'> 6top help': Shows 6top command usage" },
764 #endif /* TSCH_WITH_SIXTOP */
765  { NULL, NULL, NULL },
766 };
767 
768 /** @} */
#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:245
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:114
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 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
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:164
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:142
#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
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
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:173
int log_get_level(const char *module)
Returns the current log level.
Definition: log.c:157
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:183
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:187
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_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:177
An entry in the nbr cache.
Definition: uip-ds6-nbr.h:69