1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/shell/cmds/openwsn.c
2022-11-22 13:39:35 +01:00

618 lines
17 KiB
C

/*
* Copyright 2020 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_shell_commands
* @{
*
* @file
* @brief Shell command implementation for OpenWSN
*
* @author Francisco Molina <francois-xavier.molina@inria.fr>
*
* @}
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "shell.h"
#include "net/ieee802154.h"
#include "net/ipv6/addr.h"
#include "net/l2util.h"
#include "net/netif.h"
#include "container.h"
#include "openwsn.h"
#include "opendefs.h"
#include "scheduler.h"
#include "cross-layers/openqueue.h"
#include "cross-layers/idmanager.h"
#include "cross-layers/packetfunctions.h"
#include "02a-MAClow/IEEE802154E.h"
#include "02b-MAChigh/neighbors.h"
#include "02b-MAChigh/sixtop.h"
#include "02b-MAChigh/msf.h"
#include "03b-IPv6/icmpv6rpl.h"
#include "cjoin.h"
#define IEEE802154_LONG_ADDRESS_LEN_STR_MAX \
(sizeof("00:00:00:00:00:00:00:00"))
static const struct {
char *name;
int id;
} components[] = {
{ "?", COMPONENT_NULL },
{ "openwsn", COMPONENT_OPENWSN },
{ "idmanager", COMPONENT_IDMANAGER },
{ "openqueue", COMPONENT_OPENQUEUE },
{ "openserial", COMPONENT_OPENSERIAL },
{ "pktfuncs", COMPONENT_PACKETFUNCTIONS },
{ "random", COMPONENT_RANDOM },
{ "radio", COMPONENT_RADIO },
{ "154", COMPONENT_IEEE802154 },
{ "154e", COMPONENT_IEEE802154E },
{ "6top2154e", COMPONENT_SIXTOP_TO_IEEE802154E },
{ "154e26top", COMPONENT_IEEE802154E_TO_SIXTOP },
{ "6top", COMPONENT_SIXTOP },
{ "neigh", COMPONENT_NEIGHBORS },
{ "sched", COMPONENT_SCHEDULE },
{ "6topres", COMPONENT_SIXTOP_RES },
{ "bridge", COMPONENT_OPENBRIDGE },
{ "iphc", COMPONENT_IPHC },
{ "frag", COMPONENT_FRAG },
{ "fwd", COMPONENT_FORWARDING },
{ "icmpv6", COMPONENT_ICMPv6 },
{ "icmpv6echo", COMPONENT_ICMPv6ECHO },
{ "icmpv6router", COMPONENT_ICMPv6ROUTER },
{ "icmpv6rpl", COMPONENT_ICMPv6RPL },
{ "udp", COMPONENT_UDP },
{ "sock-udp", COMPONENT_SOCK_TO_UDP },
{ "udp-sock", COMPONENT_UDP_TO_SOCK },
{ "coap", COMPONENT_OPENCOAP },
{ "cjoin", COMPONENT_CJOIN },
{ "oscore", COMPONENT_OSCORE },
{ "c6t", COMPONENT_C6T },
{ "uinject", COMPONENT_UINJECT },
};
static char *_get_component(int id)
{
for (unsigned i = 0; i < ARRAY_SIZE(components); i++) {
if (id == components[i].id) {
return components[i].name;
}
}
return NULL;
}
static int _openwsn_ifconfig(int argc, char **argv)
{
(void)argc;
(void)argv;
open_addr_t *addr;
/* Use shared buffer for IEEE802154_LONG_ADDRES and IPV6_ADDR str
conversion */
#if IS_USED(MODULE_OPENWSN_IPV6)
char addr_str[IPV6_ADDR_MAX_STR_LEN];
#else
char addr_str[IEEE802154_LONG_ADDRESS_LEN_STR_MAX];
#endif
printf("Iface %d ", openwsn_get_pid());
addr = idmanager_getMyID(ADDR_16B);
printf("\tHWaddr: %s ",
l2util_addr_to_str(addr->addr_16b, sizeof(addr->addr_16b),
addr_str));
addr = idmanager_getMyID(ADDR_PANID);
printf("NID: %s\n\n",
l2util_addr_to_str(addr->panid, sizeof(addr->panid),
addr_str));
addr = idmanager_getMyID(ADDR_64B);
printf("\t\tLong HWaddr: %s\n",
l2util_addr_to_str(addr->addr_64b, sizeof(addr->addr_64b),
addr_str));
if (IS_USED(MODULE_OPENWSN_IPV6)) {
/* Can't recover ADDR_128B directly, recover ADDR_64B
and ADDR_PREFIX to construct ADDR_128B */
open_addr_t addr_ipv6;
addr = idmanager_getMyID(ADDR_64B);
memcpy(&addr_ipv6.addr_128b[8], addr->addr_64b,
sizeof(addr->addr_64b));
addr = idmanager_getMyID(ADDR_PREFIX);
memcpy(&addr_ipv6.addr_128b[0], addr->prefix,
sizeof(addr->prefix));
ipv6_addr_to_str(addr_str, (ipv6_addr_t *)addr_ipv6.addr_128b,
IPV6_ADDR_MAX_STR_LEN);
printf("\t\tinet6 addr: %s\n\n", addr_str);
}
printf("\t\tIEEE802154E sync: %i\n", ieee154e_isSynch());
if (IS_USED(MODULE_OPENWSN_CJOIN)) {
printf("\t\t6TiSCH joined: %i\n", cjoin_getIsJoined());
}
puts("");
if (IS_USED(MODULE_OPENWSN_IPV6)) {
uint8_t index;
if (icmpv6rpl_getPreferredParentIndex(
&index) || idmanager_getIsDAGroot()) {
open_addr_t neighbor;
uint8_t addr_ipv6[IPV6_ADDR_BIT_LEN / 8];
printf("\t\tRPL rank: %i\n", icmpv6rpl_getMyDAGrank());
if (idmanager_getIsDAGroot()) {
puts("\t\tRPL parent: Node is DAG root");
}
else {
icmpv6rpl_getPreferredParentEui64(&neighbor);
printf("\t\tRPL parent: %s\n",
l2util_addr_to_str(neighbor.addr_64b,
sizeof(neighbor.addr_64b),
addr_str));
}
printf("\t\tRPL children:\n");
for (uint8_t i = 0; i < MAXNUMNEIGHBORS; i++) {
if (neighbors_isNeighborWithHigherDAGrank(i)) {
neighbors_getNeighborEui64(&neighbor, ADDR_64B, i);
printf("\t\t\t%s\n",
l2util_addr_to_str(neighbor.addr_64b,
sizeof(neighbor.addr_64b),
addr_str));
}
}
icmpv6rpl_getRPLDODAGid(addr_ipv6);
ipv6_addr_to_str(addr_str, (ipv6_addr_t *)addr_ipv6,
IPV6_ADDR_MAX_STR_LEN);
printf("\t\tRPL DODAG ID: %16s\n", addr_str);
}
else {
puts("\t\tNO RPL parent");
}
}
return 0;
}
SHELL_COMMAND(ifconfig, "Shows assigned IPv6 addresses", _openwsn_ifconfig);
static int _neighbors_cmd(char *arg)
{
(void)arg;
char hwaddr_str[IEEE802154_LONG_ADDRESS_LEN_STR_MAX];
open_addr_t neighbor;
for (int i = 0; i < MAXNUMNEIGHBORS; i++) {
neighbors_getNeighborEui64(&neighbor, ADDR_64B, i);
l2util_addr_to_str(neighbor.addr_64b, sizeof(neighbor.addr_64b),
hwaddr_str);
if (memcmp(hwaddr_str, "00:00:00:00:00:00:00:00",
IEEE802154_LONG_ADDRESS_LEN_STR_MAX)) {
printf("%02i. %s\n", i, hwaddr_str);
}
}
return 0;
}
static void _print_cell_usage(void)
{
puts("Usage:");
puts("\tcell list: show all active cell");
puts("\tcell add <slot_offset> <channel_offset> <adv|tx|rx>"
" [<address>]: add cell directly to schedule");
puts("\tcell rmv <slot_offset> <channel_offset> <adv|tx|rx>"
" [<address>]: remove cell directly in schedule ");
}
static int _cell_list_cmd(char *arg)
{
(void)arg;
extern schedule_vars_t schedule_vars;
char hwaddr_str[IEEE802154_LONG_ADDRESS_LEN_STR_MAX];
for (int i = 0; i < MAXACTIVESLOTS; i++) {
switch (schedule_vars.scheduleBuf[i].type) {
case CELLTYPE_TX:
printf("neigh: %s, slot: %03i, chan: %02i, type: TX\n",
l2util_addr_to_str(
schedule_vars.scheduleBuf[i].neighbor.addr_64b,
IEEE802154_LONG_ADDRESS_LEN, hwaddr_str),
schedule_vars.scheduleBuf[i].slotOffset,
schedule_vars.scheduleBuf[i].channelOffset);
break;
case CELLTYPE_RX:
printf("slot: %03i, chan: %02i, type: RX\n",
schedule_vars.scheduleBuf[i].slotOffset,
schedule_vars.scheduleBuf[i].channelOffset);
break;
case CELLTYPE_TXRX:
printf("neigh: %s, slot: %03i, chan: %02i, type: RXTX\n",
l2util_addr_to_str(
schedule_vars.scheduleBuf[i].neighbor.addr_64b,
IEEE802154_LONG_ADDRESS_LEN, hwaddr_str),
schedule_vars.scheduleBuf[i].slotOffset,
schedule_vars.scheduleBuf[i].channelOffset);
break;
default:
break;
}
}
return 0;
}
static int _cell_manage_cmd(int argc, char **argv)
{
open_addr_t addr;
cellType_t type;
int res;
memset(&addr, 0, sizeof(addr));
if (argc < 5) {
_print_cell_usage();
return -1;
}
if (argc == 6) {
addr.type = ADDR_64B;
size_t len = l2util_addr_from_str(argv[5], addr.addr_64b);
if (len == 0) {
puts("Error: invalid address");
return -1;
}
}
else {
addr.type = ADDR_ANYCAST;
}
if (!strcmp(argv[4], "adv")) {
type = CELLTYPE_TXRX;
}
else if (!strcmp(argv[4], "tx")) {
type = CELLTYPE_TX;
}
else if (!strcmp(argv[4], "rx")) {
type = CELLTYPE_RX;
}
else {
_print_cell_usage();
return -1;
}
if (!strcmp(argv[1], "add")) {
res =
schedule_addActiveSlot(atoi(argv[2]), type, true, false,
atoi(argv[3]), &addr);
}
else {
res = schedule_removeActiveSlot(atoi(argv[2]), type, true, &addr);
}
if (res == 0) {
puts("Successfully set link");
return 0;
}
else {
puts("Something went wrong (duplicate link?)");
return -1;
}
}
static int _cell_cmd(int argc, char **argv)
{
if (argc < 2) {
_print_cell_usage();
return -1;
}
if (!strcmp(argv[1], "list")) {
return _cell_list_cmd(NULL);
}
if (!strcmp(argv[1], "add") || !strcmp(argv[1], "rmv")) {
return _cell_manage_cmd(argc, argv);
}
_print_cell_usage();
return -1;
}
static void _print_6top_usage(void)
{
puts("Usage:");
puts("\t6top clear [<neighbor>]:"
" request neighbor to clear all cells");
puts("\t6top add <num> <adv|tx|rx> [<neighbor>]:"
" request parent to add num cells");
puts("\t6top rmv <num> <adv|tx|rx> [<neighbor>]:"
" request parent to remove num cells");
puts("\t6top rel <num> <adv|tx|rx> [<neighbor>]:"
" request parent to relocate num cells");
}
static int _6top_manage_cmd(int argc, char **argv)
{
cellInfo_ht cells_add[CELLLIST_MAX_LEN];
cellInfo_ht cells_rmv[CELLLIST_MAX_LEN];
open_addr_t neigh;
uint8_t cell_options;
uint8_t code = IANA_6TOP_CMD_NONE;
uint8_t num;
if (argc < 4) {
puts("Error: not enough args");
_print_6top_usage();
return -1;
}
if (argc == 5) {
neigh.type = ADDR_64B;
size_t len = l2util_addr_from_str(argv[4], neigh.addr_64b);
if (len == 0) {
puts("Error: invalid address");
return -1;
}
}
else {
if (IS_USED(MODULE_OPENWSN_IPV6)) {
if (!icmpv6rpl_getPreferredParentEui64(&neigh)) {
puts("Error: no preferred parent");
return -1;
}
}
else {
puts("Error: a neighbor address must be supplied");
return -1;
}
}
if (!strcmp(argv[3], "adv")) {
cell_options = CELLOPTIONS_TX | CELLOPTIONS_RX | CELLOPTIONS_SHARED;
}
else if (!strcmp(argv[3], "tx")) {
cell_options = CELLOPTIONS_TX;
}
else if (!strcmp(argv[3], "rx")) {
cell_options = CELLOPTIONS_RX;
}
else {
puts("Error: invalid cell option");
return -1;
}
num = atoi(argv[2]);
if (!strcmp(argv[1], "add")) {
code = IANA_6TOP_CMD_ADD;
if (!msf_candidateAddCellList(cells_add, num)) {
puts("Error: can't add that many cells");
return -1;
}
}
else if (!strcmp(argv[1], "rmv")) {
code = IANA_6TOP_CMD_DELETE;
if (!msf_candidateRemoveCellList(cells_rmv, &neigh, num,
cell_options)) {
puts("Error: can't remove the specified cells");
return -1;
}
}
else if (!strcmp(argv[1], "rel")) {
code = IANA_6TOP_CMD_RELOCATE;
if (!schedule_getCellsToBeRelocated(&neigh, cells_rmv) ||
!msf_candidateAddCellList(cells_add, num)) {
puts("Error: failed to get cells to relocate");
return -1;
}
}
else {
puts("Error: unknown 6top command");
return -1;
}
int ret = sixtop_request(code, &neigh, num, cell_options, cells_add,
cells_rmv, IANA_6TISCH_SFID_MSF, 0, 0);
if (ret) {
puts("Error: 6top request failed");
return -1;
}
return 0;
}
static int _6top_cmd(int argc, char **argv)
{
if (argc < 2) {
_print_6top_usage();
return -1;
}
if (!strcmp(argv[1], "clear")) {
open_addr_t neighbor;
if (argc == 3) {
neighbor.type = ADDR_64B;
size_t len = l2util_addr_from_str(argv[2], neighbor.addr_64b);
if (len == 0) {
puts("Error: invalid address");
return -1;
}
}
else {
if (IS_USED(MODULE_OPENWSN_IPV6)) {
if (!icmpv6rpl_getPreferredParentEui64(&neighbor)) {
puts("Error: no preferred parent");
return -1;
}
}
else {
puts("Error: a neighbor address must be supplied");
return -1;
}
}
int ret = sixtop_request(IANA_6TOP_CMD_CLEAR, &neighbor, 0, 0,
NULL, NULL, IANA_6TISCH_SFID_MSF, 0, 0);
if (ret) {
puts("Error: 6top request failed");
return -1;
}
}
if (!strcmp(argv[1], "add") || !strcmp(argv[1], "rmv") ||
!strcmp(argv[1], "rel")) {
return _6top_manage_cmd(argc, argv);
}
_print_6top_usage();
return -1;
}
static void _print_queue_usage(void)
{
puts("Usage:");
puts("\tqueue list: show all Openqueue entries");
puts("\tqueue rmv <creator>: remove all entries"
" from <creator> in queue");
}
static int _queue_cmd(int argc, char **argv)
{
if (argc < 2) {
_print_queue_usage();
return -1;
}
if (!strcmp(argv[1], "list")) {
extern openqueue_vars_t openqueue_vars;
bool empty_queue = true;
for (uint8_t i = 0; i < QUEUELENGTH; i++) {
if (openqueue_vars.queue[i].creator ||
openqueue_vars.queue[i].owner) {
uint8_t creator = openqueue_vars.queue[i].creator;
uint8_t owner = openqueue_vars.queue[i].owner;
printf("Creator: %.9s [%d], ",
_get_component(creator), creator);
printf("Owner: %.9s [%d]\n",
_get_component(owner), owner);
empty_queue = false;
}
}
if (empty_queue) {
puts("Queue is empty");
}
return 0;
}
if (!strcmp(argv[1], "rmv")) {
if (argc != 3) {
_print_queue_usage();
return -1;
}
uint8_t creator = atoi(argv[2]);
if (creator == 0) {
puts("Error: invalid input value\n");
return -1;
}
else {
printf("Removing entries created by: %.9s [%d]\n",
_get_component(creator), creator);
openqueue_removeAllCreatedBy(creator);
return 0;
}
}
_print_queue_usage();
return -1;
}
#if SCHEDULER_DEBUG_ENABLE
static int _scheduler_cmd(char *arg)
{
(void)arg;
extern scheduler_dbg_t scheduler_dbg;
printf("Current tasks: %i\n", scheduler_dbg.numTasksCur);
printf("Max tasks: %i\n", scheduler_dbg.numTasksMax);
return 0;
}
#endif
static void _print_usage(void)
{
puts("Usage:");
puts("\topenwsn neigh: show neighbor table");
puts("\topenwsn queue: Openqueue management commands");
puts("\topenwsn cell: cell management commands");
puts("\topenwsn 6top: 6top request commands");
#if SCHEDULER_DEBUG_ENABLE
puts("\topenwsn sched: show openos scheduler information");
#endif
}
static int _openwsn_handler(int argc, char **argv)
{
if (argc < 2) {
_print_usage();
return -1;
}
if (!strcmp(argv[1], "neigh")) {
return _neighbors_cmd(NULL);
}
if (!strcmp(argv[1], "queue")) {
return _queue_cmd(argc - 1, &argv[1]);
}
if (!strcmp(argv[1], "cell")) {
if (!ieee154e_isSynch()) {
puts("Error: node is not synchronized");
return -1;
}
return _cell_cmd(argc - 1, &argv[1]);
}
#if SCHEDULER_DEBUG_ENABLE
if (!strcmp(argv[1], "sched")) {
return _scheduler_cmd(NULL);
}
#endif
if (!strcmp(argv[1], "6top")) {
if (!ieee154e_isSynch()) {
puts("Error: node is not synchronized");
return -1;
}
return _6top_cmd(argc - 1, &argv[1]);
}
_print_usage();
return -1;
}
SHELL_COMMAND(openwsn, "OpenWSN commands", _openwsn_handler);