1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00
RIOT/sys/shell/commands/sc_netif.c
Francesco Ermini 9fa4684203 drivers/xbee: encryption support
add encryption to drivers

fix new line at the end of file

add shell command for enable encryption and set encryption key on a given device

modify _net_if_set_encrypt_key to support any key length

modify _net_if_set_encrypt_key to support any key length of the key

modify blank line

fix ace before tab in indent

fix ace before tab indent

fix ace before tab indent an error

fix trailing white space

drivers/xbee: encryption support

add encryption to drivers

fix new line at the end of file

add shell command for enable encryption and set encryption key on a given device

modify _net_if_set_encrypt_key to support any key length

modify _net_if_set_encrypt_key to support any key length of the key

modify blank line

fix ace before tab in indent

fix ace before tab indent

fix ace before tab indent an error

fix trailing white space

modify drivers/xbee/xbee.c

fix white spaces on xbee.c

Update xbee encryption driver

white line at end xbee.h

fix error

fix sc_netif.c

fix rebase master interactive

drivers/xbee: encryption support

add encryption to drivers

fix new line at the end of file

add shell command for enable encryption and set encryption key on a given device

modify _net_if_set_encrypt_key to support any key length

modify _net_if_set_encrypt_key to support any key length of the key

modify blank line

fix ace before tab in indent

fix ace before tab indent

fix ace before tab indent an error

fix trailing white space

drivers/xbee: encryption support

add encryption to drivers

fix new line at the end of file

add shell command for enable encryption and set encryption key on a given device

modify _net_if_set_encrypt_key to support any key length

modify _net_if_set_encrypt_key to support any key length of the key

modify blank line

fix ace before tab in indent

fix ace before tab indent

fix ace before tab indent an error

fix trailing white space

modify drivers/xbee/xbee.c

fix white spaces on xbee.c

Update xbee encryption driver

white line at end xbee.h

fix error

fix rebase  conflict 4

fix same missing in patches changes

fix ascii to hex index parser

fix syntax rules

fix syntax issue 2

add _netopt_strmap NETOPT_ENCRYPTION e NETOPT_ENCRYPTION_KEY

fix trailng white spaces
2016-04-20 17:43:09 +02:00

1161 lines
31 KiB
C

/*
* Copyright (C) 2015 Freie Universität Berlin
*
* 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 commands for interacting with network devices
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "thread.h"
#include "net/netstats.h"
#include "net/ipv6/addr.h"
#include "net/gnrc/ipv6/netif.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netapi.h"
#include "net/netopt.h"
#include "net/gnrc/pkt.h"
#include "net/gnrc/pktbuf.h"
#include "net/gnrc/netif/hdr.h"
#include "net/gnrc/sixlowpan/netif.h"
/**
* @brief The maximal expected link layer address length in byte
*/
#define MAX_ADDR_LEN (8U)
/**
* @brief The default IPv6 prefix length if not specified.
*/
#define SC_NETIF_IPV6_DEFAULT_PREFIX_LEN (64)
/* utility functions */
static bool _is_number(char *str)
{
for (; *str; str++) {
if (*str < '0' || *str > '9') {
return false;
}
}
return true;
}
static bool _is_iface(kernel_pid_t dev)
{
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
size_t numof = gnrc_netif_get(ifs);
for (size_t i = 0; i < numof && i < GNRC_NETIF_NUMOF; i++) {
if (ifs[i] == dev) {
return true;
}
}
return false;
}
#ifdef MODULE_NETSTATS_L2
static int _netif_stats(kernel_pid_t dev, bool reset)
{
netstats_t *stats;
int res = -ENOTSUP;
res = gnrc_netapi_get(dev, NETOPT_STATS, 0, &stats, sizeof(&stats));
if (res < 0) {
puts(" Protocol or device doesn't provide statistics.");
}
else if (reset) {
memset(stats, 0, sizeof(netstats_t));
puts("Reset statistics!");
}
else {
printf(" RX packets %u bytes %u\n"
" TX packets %u (Multicast: %u) bytes %u\n"
" TX succeeded %u errors %u\n",
(unsigned) stats->rx_count,
(unsigned) stats->rx_bytes,
(unsigned) (stats->tx_unicast_count + stats->tx_mcast_count),
(unsigned) stats->tx_mcast_count,
(unsigned) stats->tx_bytes,
(unsigned) stats->tx_success,
(unsigned) stats->tx_failed);
}
return res;
}
#endif
static void _set_usage(char *cmd_name)
{
printf("usage: %s <if_id> set <key> <value>\n", cmd_name);
puts(" Sets an hardware specific specific value\n"
" <key> may be one of the following\n"
" * \"addr\" - sets (short) address\n"
" * \"addr_long\" - sets long address\n"
" * \"addr_short\" - alias for \"addr\"\n"
" * \"channel\" - sets the frequency channel\n"
" * \"chan\" - alias for \"channel\"\n"
" * \"csma_retries\" - set max. number of channel access attempts\n"
" * \"cca_threshold\" - set ED threshold during CCA in dBm\n"
" * \"nid\" - sets the network identifier (or the PAN ID)\n"
" * \"page\" - set the channel page (IEEE 802.15.4)\n"
" * \"pan\" - alias for \"nid\"\n"
" * \"pan_id\" - alias for \"nid\"\n"
" * \"power\" - TX power in dBm\n"
" * \"retrans\" - max. number of retransmissions\n"
" * \"src_len\" - sets the source address length in byte\n"
" * \"state\" - set the device state\n"
" * \"encrypt\" - set the encryption on-off\n"
" * \"key\" - set the encryption key in hexadecimal format\n");
}
static void _mtu_usage(char *cmd_name)
{
printf("usage: %s <if_id> mtu <n>\n", cmd_name);
}
static void _hl_usage(char *cmd_name)
{
printf("usage: %s <if_id> hl <n>\n", cmd_name);
}
static void _flag_usage(char *cmd_name)
{
printf("usage: %s <if_id> [-]{promisc|autoack|csma|autocca|cca_threshold|preload|iphc|rtr_adv}\n", cmd_name);
}
static void _add_usage(char *cmd_name)
{
printf("usage: %s <if_id> add [anycast|multicast|unicast] "
"<ipv6_addr>[/prefix_len]\n", cmd_name);
}
static void _del_usage(char *cmd_name)
{
printf("usage: %s <if_id> del <ipv6_addr>\n",
cmd_name);
}
static void _stats_usage(char *cmd_name)
{
printf("usage: %s <if_id> stats [reset]\n", cmd_name);
}
static void _print_netopt(netopt_t opt)
{
switch (opt) {
case NETOPT_ADDRESS:
printf("(short) address");
break;
case NETOPT_ADDRESS_LONG:
printf("long address");
break;
case NETOPT_SRC_LEN:
printf("source address length");
break;
case NETOPT_CHANNEL:
printf("channel");
break;
case NETOPT_CHANNEL_PAGE:
printf("page");
break;
case NETOPT_NID:
printf("network identifier");
break;
case NETOPT_TX_POWER:
printf("TX power [in dBm]");
break;
case NETOPT_RETRANS:
printf("max. retransmissions");
break;
case NETOPT_CSMA_RETRIES:
printf("CSMA retries");
break;
case NETOPT_CCA_THRESHOLD:
printf("CCA threshold [in dBm]");
break;
case NETOPT_ENCRYPTION:
printf("encryption");
break;
case NETOPT_ENCRYPTION_KEY:
printf("encryption key");
break;
default:
/* we don't serve these options here */
break;
}
}
static void _print_netopt_state(netopt_state_t state)
{
switch (state) {
case NETOPT_STATE_OFF:
printf("OFF");
break;
case NETOPT_STATE_SLEEP:
printf("SLEEP");
break;
case NETOPT_STATE_IDLE:
printf("IDLE");
break;
case NETOPT_STATE_RX:
printf("RX");
break;
case NETOPT_STATE_TX:
printf("TX");
break;
case NETOPT_STATE_RESET:
printf("RESET");
break;
default:
/* nothing to do then */
break;
}
}
static void _netif_list(kernel_pid_t dev)
{
uint8_t hwaddr[MAX_ADDR_LEN];
uint16_t u16;
int16_t i16;
uint8_t u8;
int res;
netopt_state_t state;
netopt_enable_t enable = NETOPT_DISABLE;
bool linebreak = false;
#ifdef MODULE_GNRC_IPV6_NETIF
gnrc_ipv6_netif_t *entry = gnrc_ipv6_netif_get(dev);
char ipv6_addr[IPV6_ADDR_MAX_STR_LEN];
#endif
printf("Iface %2d ", dev);
res = gnrc_netapi_get(dev, NETOPT_ADDRESS, 0, hwaddr, sizeof(hwaddr));
if (res >= 0) {
char hwaddr_str[res * 3];
printf(" HWaddr: ");
printf("%s", gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str),
hwaddr, res));
printf(" ");
}
res = gnrc_netapi_get(dev, NETOPT_CHANNEL, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" Channel: %" PRIu16 " ", u16);
}
res = gnrc_netapi_get(dev, NETOPT_CHANNEL_PAGE, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" Page: %" PRIu16 " ", u16);
}
res = gnrc_netapi_get(dev, NETOPT_NID, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" NID: 0x%" PRIx16, u16);
}
printf("\n ");
res = gnrc_netapi_get(dev, NETOPT_ADDRESS_LONG, 0, hwaddr, sizeof(hwaddr));
if (res >= 0) {
char hwaddr_str[res * 3];
printf("Long HWaddr: ");
printf("%s ", gnrc_netif_addr_to_str(hwaddr_str, sizeof(hwaddr_str),
hwaddr, res));
linebreak = true;
}
if (linebreak) {
printf("\n ");
}
res = gnrc_netapi_get(dev, NETOPT_TX_POWER, 0, &i16, sizeof(i16));
if (res >= 0) {
printf(" TX-Power: %" PRIi16 "dBm ", i16);
}
res = gnrc_netapi_get(dev, NETOPT_STATE, 0, &state, sizeof(state));
if (res >= 0) {
printf(" State: ");
_print_netopt_state(state);
printf(" ");
}
res = gnrc_netapi_get(dev, NETOPT_RETRANS, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" max. Retrans.: %u ", (unsigned)u8);
}
res = gnrc_netapi_get(dev, NETOPT_CSMA_RETRIES, 0, &u8, sizeof(u8));
if (res >= 0) {
res = gnrc_netapi_get(dev, NETOPT_CSMA, 0, &enable, sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf(" CSMA Retries: %u ", (unsigned)u8);
}
}
printf("\n ");
res = gnrc_netapi_get(dev, NETOPT_PROMISCUOUSMODE, 0, &enable, sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf("PROMISC ");
linebreak = true;
}
res = gnrc_netapi_get(dev, NETOPT_AUTOACK, 0, &enable, sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf("AUTOACK ");
linebreak = true;
}
res = gnrc_netapi_get(dev, NETOPT_PRELOADING, 0, &enable, sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf("PRELOAD ");
linebreak = true;
}
res = gnrc_netapi_get(dev, NETOPT_RAWMODE, 0, &enable, sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf("RAWMODE ");
linebreak = true;
}
res = gnrc_netapi_get(dev, NETOPT_CSMA, 0, &enable, sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf("CSMA ");
linebreak = true;
}
res = gnrc_netapi_get(dev, NETOPT_AUTOCCA, 0, &enable, sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf("AUTOCCA ");
linebreak = true;
}
#ifdef MODULE_GNRC_IPV6_NETIF
if (entry != NULL) {
printf("MTU:%" PRIu16 " ", entry->mtu);
printf("HL:%u ", (unsigned)entry->cur_hl);
if (entry->flags & GNRC_IPV6_NETIF_FLAGS_SIXLOWPAN) {
printf("6LO ");
}
if (entry->flags & GNRC_IPV6_NETIF_FLAGS_ROUTER) {
printf("RTR ");
}
if (entry->flags & GNRC_IPV6_NETIF_FLAGS_RTR_ADV) {
printf("RTR_ADV ");
}
linebreak = true;
}
#endif
#if defined(MODULE_GNRC_SIXLOWPAN_NETIF) && defined(MODULE_GNRC_SIXLOWPAN_IPHC)
gnrc_sixlowpan_netif_t *sixlo_entry = gnrc_sixlowpan_netif_get(dev);
if ((sixlo_entry != NULL) && (sixlo_entry->iphc_enabled)) {
printf("IPHC ");
linebreak = true;
}
#endif
if (linebreak) {
printf("\n ");
}
res = gnrc_netapi_get(dev, NETOPT_SRC_LEN, 0, &u16, sizeof(u16));
if (res >= 0) {
printf("Source address length: %" PRIu16 "\n ", u16);
}
#ifdef MODULE_GNRC_IPV6_NETIF
if (entry == NULL) {
puts("");
return;
}
printf("Link type: %s", (entry->flags & GNRC_IPV6_NETIF_FLAGS_IS_WIRED) ?
"wired" : "wireless");
printf("\n ");
for (int i = 0; i < GNRC_IPV6_NETIF_ADDR_NUMOF; i++) {
if (!ipv6_addr_is_unspecified(&entry->addrs[i].addr)) {
printf("inet6 addr: ");
if (ipv6_addr_to_str(ipv6_addr, &entry->addrs[i].addr,
IPV6_ADDR_MAX_STR_LEN)) {
printf("%s/%u scope: ", ipv6_addr, (unsigned)entry->addrs[i].prefix_len);
if ((ipv6_addr_is_link_local(&entry->addrs[i].addr))) {
printf("local");
}
else {
printf("global");
}
if (entry->addrs[i].flags & GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST) {
if (ipv6_addr_is_multicast(&entry->addrs[i].addr)) {
printf(" [multicast]");
}
else {
printf(" [anycast]");
}
}
}
else {
printf("error in conversion");
}
printf("\n ");
}
}
#endif
#ifdef MODULE_NETSTATS_L2
puts("");
_netif_stats(dev, false);
#endif
puts("");
}
static int _netif_set_u16(kernel_pid_t dev, netopt_t opt, char *u16_str)
{
unsigned int res;
bool hex = false;
if (_is_number(u16_str)) {
if ((res = strtoul(u16_str, NULL, 10)) == ULONG_MAX) {
puts("error: unable to parse value.\n"
"Must be a 16-bit unsigned integer (dec or hex)\n");
return 1;
}
}
else {
if ((res = strtoul(u16_str, NULL, 16)) == ULONG_MAX) {
puts("error: unable to parse value.\n"
"Must be a 16-bit unsigned integer (dec or hex)\n");
return 1;
}
hex = true;
}
if (res > 0xffff) {
puts("error: unable to parse value.\n"
"Must be a 16-bit unsigned integer (dec or hex)\n");
return 1;
}
if (gnrc_netapi_set(dev, opt, 0, (uint16_t *)&res, sizeof(uint16_t)) < 0) {
printf("error: unable to set ");
_print_netopt(opt);
puts("");
return 1;
}
printf("success: set ");
_print_netopt(opt);
printf(" on interface %" PRIkernel_pid " to ", dev);
if (hex) {
printf("0x%04x\n", res);
}
else {
printf("%u\n", res);
}
return 0;
}
static int _netif_set_i16(kernel_pid_t dev, netopt_t opt, char *i16_str)
{
int16_t val = (int16_t)atoi(i16_str);
if (gnrc_netapi_set(dev, opt, 0, (int16_t *)&val, sizeof(int16_t)) < 0) {
printf("error: unable to set ");
_print_netopt(opt);
puts("");
return 1;
}
printf("success: set ");
_print_netopt(opt);
printf(" on interface %" PRIkernel_pid " to %i\n", dev, val);
return 0;
}
static int _netif_set_u8(kernel_pid_t dev, netopt_t opt, char *u8_str)
{
uint8_t val = (uint8_t)atoi(u8_str);
if (gnrc_netapi_set(dev, opt, 0, (uint8_t *)&val, sizeof(uint8_t)) < 0) {
printf("error: unable to set ");
_print_netopt(opt);
puts("");
return 1;
}
printf("success: set ");
_print_netopt(opt);
printf(" on interface %" PRIkernel_pid " to %i\n", dev, val);
return 0;
}
static int _netif_set_flag(kernel_pid_t dev, netopt_t opt,
netopt_enable_t set)
{
if (gnrc_netapi_set(dev, opt, 0, &set, sizeof(netopt_enable_t)) < 0) {
puts("error: unable to set option");
return 1;
}
printf("success: %sset option\n", (set) ? "" : "un");
return 0;
}
static int _netif_set_addr(kernel_pid_t dev, netopt_t opt, char *addr_str)
{
uint8_t addr[MAX_ADDR_LEN];
size_t addr_len = gnrc_netif_addr_from_str(addr, sizeof(addr), addr_str);
if (addr_len == 0) {
puts("error: unable to parse address.\n"
"Must be of format [0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*\n"
"(hex pairs delimited by colons)");
return 1;
}
if (gnrc_netapi_set(dev, opt, 0, addr, addr_len) < 0) {
printf("error: unable to set ");
_print_netopt(opt);
puts("");
return 1;
}
printf("success: set ");
_print_netopt(opt);
printf(" on interface %" PRIkernel_pid " to %s\n", dev, addr_str);
return 0;
}
static int _netif_set_state(kernel_pid_t dev, char *state_str)
{
netopt_state_t state;
if ((strcmp("off", state_str) == 0) || (strcmp("OFF", state_str) == 0)) {
state = NETOPT_STATE_OFF;
}
else if ((strcmp("sleep", state_str) == 0) ||
(strcmp("SLEEP", state_str) == 0)) {
state = NETOPT_STATE_SLEEP;
}
else if ((strcmp("idle", state_str) == 0) ||
(strcmp("IDLE", state_str) == 0)) {
state = NETOPT_STATE_IDLE;
}
else if ((strcmp("reset", state_str) == 0) ||
(strcmp("RESET", state_str) == 0)) {
state = NETOPT_STATE_RESET;
}
else {
puts("usage: ifconfig <if_id> set state [off|sleep|idle|reset]");
return 1;
}
if (gnrc_netapi_set(dev, NETOPT_STATE, 0,
&state, sizeof(netopt_state_t)) < 0) {
printf("error: unable to set state to ");
_print_netopt_state(state);
puts("");
return 1;
}
printf("success: set state of interface %" PRIkernel_pid " to ", dev);
_print_netopt_state(state);
puts("");
return 0;
}
static int _netif_set_encrypt(kernel_pid_t dev, netopt_t opt, char *encrypt_str)
{
netopt_enable_t set;
size_t size = 1;
if ((strcmp("on", encrypt_str) == 0) || (strcmp("ON", encrypt_str) == 0)) {
set = NETOPT_ENABLE;
}
else if ((strcmp("off", encrypt_str) == 0) || (strcmp("OFF", encrypt_str) == 0)) {
set = NETOPT_DISABLE;
}
else {
puts("usage: ifconfig <if_id> set encryption [on|off]");
return 1;
}
if (gnrc_netapi_set(dev, opt, 0, &set, size) < 0) {
printf("error: unable to set ");
_print_netopt(opt);
puts("");
return 1;
}
printf("success: set ");
_print_netopt(opt);
printf(" on interface %" PRIkernel_pid " to %s\n", dev, encrypt_str);
return 0;
}
static int _hex_to_int(char c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
else if ('a' <= c && c <= 'f') {
return c - 'a';
}
else if ('A' <= c && c <= 'F') {
return c - 'A';
}
else {
return -1;
}
}
static int _netif_set_encrypt_key(kernel_pid_t dev, netopt_t opt, char *key_str)
{
size_t str_len = strlen(key_str);
size_t key_len = str_len / 2;
uint8_t key[key_len];
if (str_len == 14U) {
printf("\nNotice: setting 56 bit key.");
}
else if (str_len == 16U) {
printf("\nNotice: setting 64 bit key.");
}
else if (str_len == 32U) {
printf("\nNotice: setting 128 bit key.");
}
else if (str_len == 48U) {
printf("\nNotice: setting 192 bit key.");
}
else if (str_len == 64U) {
printf("\nNotice: setting 256 bit key.");
}
else if (str_len == 128U) {
printf("\nNotice: setting 512 bit key.");
}
else {
printf("error: invalid key size.\n");
return 1;
}
/* Convert any char from ASCII table in hex format */
for (size_t i = 0; i < str_len; i += 2) {
int i1 = _hex_to_int(key_str[i]);
int i2 = _hex_to_int(key_str[i + 1]);
if (i1 == -1 || i2 == -1) {
puts("error: unable to parse key");
return 1;
}
key[i / 2] = (uint8_t)((i1 << 4) + i2);
}
if (gnrc_netapi_set(dev, opt, 0, key, key_len) < 0) {
printf("error: unable to set ");
_print_netopt(opt);
puts("");
return 1;
}
printf("success: set ");
_print_netopt(opt);
printf(" on interface %" PRIkernel_pid " to \n", dev);
for (size_t i = 0; i < key_len; i++) {
/* print the hex value of the key */
printf("%02x", key[i]);
}
puts("");
return 0;
}
static int _netif_set(char *cmd_name, kernel_pid_t dev, char *key, char *value)
{
if ((strcmp("addr", key) == 0) || (strcmp("addr_short", key) == 0)) {
return _netif_set_addr(dev, NETOPT_ADDRESS, value);
}
else if (strcmp("addr_long", key) == 0) {
return _netif_set_addr(dev, NETOPT_ADDRESS_LONG, value);
}
else if ((strcmp("channel", key) == 0) || (strcmp("chan", key) == 0)) {
return _netif_set_u16(dev, NETOPT_CHANNEL, value);
}
else if (strcmp("page", key) == 0) {
return _netif_set_u16(dev, NETOPT_CHANNEL_PAGE, value);
}
else if ((strcmp("nid", key) == 0) || (strcmp("pan", key) == 0) ||
(strcmp("pan_id", key) == 0)) {
return _netif_set_u16(dev, NETOPT_NID, value);
}
else if (strcmp("power", key) == 0) {
return _netif_set_i16(dev, NETOPT_TX_POWER, value);
}
else if (strcmp("src_len", key) == 0) {
return _netif_set_u16(dev, NETOPT_SRC_LEN, value);
}
else if (strcmp("state", key) == 0) {
return _netif_set_state(dev, value);
}
else if (strcmp("retrans", key) == 0) {
return _netif_set_u8(dev, NETOPT_RETRANS, value);
}
else if (strcmp("csma_retries", key) == 0) {
return _netif_set_u8(dev, NETOPT_CSMA_RETRIES, value);
}
else if (strcmp("cca_threshold", key) == 0) {
return _netif_set_u8(dev, NETOPT_CCA_THRESHOLD, value);
}
else if (strcmp("encrypt", key) == 0) {
return _netif_set_encrypt(dev, NETOPT_ENCRYPTION, value);
}
else if (strcmp("key", key) == 0) {
return _netif_set_encrypt_key(dev, NETOPT_ENCRYPTION_KEY, value);
}
_set_usage(cmd_name);
return 1;
}
static int _netif_flag(char *cmd, kernel_pid_t dev, char *flag)
{
netopt_enable_t set = NETOPT_ENABLE;
if (flag[0] == '-') {
set = NETOPT_DISABLE;
flag++;
}
if (strcmp(flag, "promisc") == 0) {
return _netif_set_flag(dev, NETOPT_PROMISCUOUSMODE, set);
}
else if (strcmp(flag, "preload") == 0) {
return _netif_set_flag(dev, NETOPT_PRELOADING, set);
}
else if (strcmp(flag, "autoack") == 0) {
return _netif_set_flag(dev, NETOPT_AUTOACK, set);
}
else if (strcmp(flag, "raw") == 0) {
return _netif_set_flag(dev, NETOPT_RAWMODE, set);
}
else if (strcmp(flag, "csma") == 0) {
return _netif_set_flag(dev, NETOPT_CSMA, set);
}
else if (strcmp(flag, "autocca") == 0) {
return _netif_set_flag(dev, NETOPT_AUTOCCA, set);
}
else if (strcmp(flag, "iphc") == 0) {
#if defined(MODULE_GNRC_SIXLOWPAN_NETIF) && defined(MODULE_GNRC_SIXLOWPAN_IPHC)
gnrc_sixlowpan_netif_t *entry = gnrc_sixlowpan_netif_get(dev);
if (entry == NULL) {
puts("error: unable to (un)set IPHC");
return 1;
}
if (set) {
entry->iphc_enabled = true;
printf("success: enable IPHC on interface %" PRIkernel_pid "\n", dev);
}
else {
entry->iphc_enabled = false;
printf("success: disable IPHC on interface %" PRIkernel_pid "\n", dev);
}
return 0;
#else
puts("error: unable to (un)set IPHC.");
return 1;
#endif
}
else if (strcmp(flag, "rtr_adv") == 0) {
#if defined(MODULE_GNRC_NDP_ROUTER) || defined(MODULE_GNRC_SIXLOWPAN_ND_ROUTER)
gnrc_ipv6_netif_t *entry = gnrc_ipv6_netif_get(dev);
if (entry == NULL) {
puts("error: unable to (un)set router advertisement flag.");
return 1;
}
if (set) {
gnrc_ipv6_netif_set_rtr_adv(entry, true);
printf("success: enable router advertisements on interface %" PRIkernel_pid "\n", dev);
}
else {
gnrc_ipv6_netif_set_rtr_adv(entry, false);
printf("success: disable router advertisements on interface %" PRIkernel_pid "\n",
dev);
}
return 0;
#else
puts("error: unable to (un)set router advertisement flag.");
return 1;
#endif
}
_flag_usage(cmd);
return 1;
}
#ifdef MODULE_GNRC_IPV6_NETIF
static uint8_t _get_prefix_len(char *addr)
{
int prefix_len = ipv6_addr_split(addr, '/', SC_NETIF_IPV6_DEFAULT_PREFIX_LEN);
if ((prefix_len < 1) || (prefix_len > IPV6_ADDR_BIT_LEN)) {
prefix_len = SC_NETIF_IPV6_DEFAULT_PREFIX_LEN;
}
return prefix_len;
}
#endif
static int _netif_add(char *cmd_name, kernel_pid_t dev, int argc, char **argv)
{
#ifdef MODULE_GNRC_IPV6_NETIF
enum {
_UNICAST = 0,
_MULTICAST, /* multicast value just to check if given addr is mc */
_ANYCAST
} type = _UNICAST;
char *addr_str = argv[0];
ipv6_addr_t addr;
ipv6_addr_t *ifaddr;
uint8_t prefix_len, flags = 0;
if (argc > 1) {
if (strcmp(argv[0], "anycast") == 0) {
type = _ANYCAST;
addr_str = argv[1];
}
else if (strcmp(argv[0], "multicast") == 0) {
type = _MULTICAST;
addr_str = argv[1];
}
else if (strcmp(argv[0], "unicast") == 0) {
/* type already set to unicast */
addr_str = argv[1];
}
else {
_add_usage(cmd_name);
return 1;
}
}
prefix_len = _get_prefix_len(addr_str);
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
puts("error: unable to parse IPv6 address.");
return 1;
}
if ((argc > 1) && (ipv6_addr_is_multicast(&addr)) && (type != _MULTICAST)) {
puts("error: address was not a multicast address.");
return 1;
}
flags = GNRC_IPV6_NETIF_ADDR_FLAGS_NDP_AUTO;
if (type == _ANYCAST) {
flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_NON_UNICAST;
}
else {
flags |= GNRC_IPV6_NETIF_ADDR_FLAGS_UNICAST;
}
if ((ifaddr = gnrc_ipv6_netif_add_addr(dev, &addr, prefix_len, flags)) == NULL) {
printf("error: unable to add IPv6 address\n");
return 1;
}
/* Address shall be valid infinitely */
gnrc_ipv6_netif_addr_get(ifaddr)->valid = UINT32_MAX;
/* Address shall be preferred infinitely */
gnrc_ipv6_netif_addr_get(ifaddr)->preferred = UINT32_MAX;
printf("success: added %s/%d to interface %" PRIkernel_pid "\n", addr_str,
prefix_len, dev);
return 0;
#else
(void)cmd_name;
(void)dev;
(void)argc;
(void)argv;
puts("error: unable to add IPv6 address.");
return 1;
#endif
}
static int _netif_del(kernel_pid_t dev, char *addr_str)
{
#ifdef MODULE_GNRC_IPV6_NETIF
ipv6_addr_t addr;
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
puts("error: unable to parse IPv6 address.");
return 1;
}
gnrc_ipv6_netif_remove_addr(dev, &addr);
printf("success: removed %s to interface %" PRIkernel_pid "\n", addr_str,
dev);
return 0;
#else
(void)dev;
(void)addr_str;
puts("error: unable to delete IPv6 address.");
return 1;
#endif
}
static int _netif_mtu(kernel_pid_t dev, char *mtu_str)
{
#ifdef MODULE_GNRC_IPV6_NETIF
int mtu;
gnrc_ipv6_netif_t *entry;
if (((mtu = atoi(mtu_str)) < IPV6_MIN_MTU) || (mtu > UINT16_MAX)) {
printf("error: MTU must be between %" PRIu16 " and %" PRIu16 "\n",
(uint16_t)IPV6_MIN_MTU, (uint16_t)UINT16_MAX);
return 1;
}
if ((entry = gnrc_ipv6_netif_get(dev)) == NULL) {
puts("error: unable to set MTU.");
return 1;
}
entry->mtu = mtu;
printf("success: set MTU %u interface %" PRIkernel_pid "\n", mtu,
dev);
return 0;
#else
(void)dev;
(void)mtu_str;
puts("error: unable to set MTU.");
return 1;
#endif
}
/* shell commands */
int _netif_send(int argc, char **argv)
{
kernel_pid_t dev;
uint8_t addr[MAX_ADDR_LEN];
size_t addr_len;
gnrc_pktsnip_t *pkt, *hdr;
gnrc_netif_hdr_t *nethdr;
uint8_t flags = 0x00;
if (argc < 4) {
printf("usage: %s <if> [<L2 addr>|bcast] <data>\n", argv[0]);
return 1;
}
/* parse interface */
dev = (kernel_pid_t)atoi(argv[1]);
if (!_is_iface(dev)) {
puts("error: invalid interface given");
return 1;
}
/* parse address */
addr_len = gnrc_netif_addr_from_str(addr, sizeof(addr), argv[2]);
if (addr_len == 0) {
if (strcmp(argv[2], "bcast") == 0) {
flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;
}
else {
puts("error: invalid address given");
return 1;
}
}
/* put packet together */
pkt = gnrc_pktbuf_add(NULL, argv[3], strlen(argv[3]), GNRC_NETTYPE_UNDEF);
if (pkt == NULL) {
puts("error: packet buffer full");
return 1;
}
hdr = gnrc_netif_hdr_build(NULL, 0, addr, addr_len);
if (hdr == NULL) {
puts("error: packet buffer full");
gnrc_pktbuf_release(pkt);
return 1;
}
LL_PREPEND(pkt, hdr);
nethdr = (gnrc_netif_hdr_t *)hdr->data;
nethdr->flags = flags;
/* and send it */
if (gnrc_netapi_send(dev, pkt) < 1) {
puts("error: unable to send");
gnrc_pktbuf_release(pkt);
return 1;
}
return 0;
}
int _netif_config(int argc, char **argv)
{
if (argc < 2) {
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
size_t numof = gnrc_netif_get(ifs);
for (size_t i = 0; i < numof && i < GNRC_NETIF_NUMOF; i++) {
_netif_list(ifs[i]);
}
return 0;
}
else if (_is_number(argv[1])) {
kernel_pid_t dev = (kernel_pid_t)atoi(argv[1]);
if (_is_iface(dev)) {
if (argc < 3) {
_netif_list(dev);
return 0;
}
else if (strcmp(argv[2], "set") == 0) {
if (argc < 5) {
_set_usage(argv[0]);
return 1;
}
return _netif_set(argv[0], dev, argv[3], argv[4]);
}
else if (strcmp(argv[2], "add") == 0) {
if (argc < 4) {
_add_usage(argv[0]);
return 1;
}
return _netif_add(argv[0], (kernel_pid_t)dev, argc - 3, argv + 3);
}
else if (strcmp(argv[2], "del") == 0) {
if (argc < 4) {
_del_usage(argv[0]);
return 1;
}
return _netif_del((kernel_pid_t)dev, argv[3]);
}
else if (strcmp(argv[2], "mtu") == 0) {
if (argc < 4) {
_mtu_usage(argv[0]);
return 1;
}
return _netif_mtu((kernel_pid_t)dev, argv[3]);
}
#ifdef MODULE_NETSTATS_L2
else if (strcmp(argv[2], "stats") == 0) {
bool reset = false;
if ((argc > 3) && (strncmp(argv[3], "reset", 5) == 0)) {
reset = true;
}
return _netif_stats((kernel_pid_t)dev, reset);
}
#endif
#ifdef MODULE_GNRC_IPV6_NETIF
else if (strcmp(argv[2], "hl") == 0) {
if (argc < 4) {
_hl_usage(argv[0]);
return 1;
}
int hl;
gnrc_ipv6_netif_t *entry;
if (((hl = atoi(argv[3])) < 0) || (hl > UINT8_MAX)) {
printf("error: Hop limit must be between %" PRIu16 " and %" PRIu16 "\n",
(uint16_t)0, (uint16_t)UINT16_MAX);
return 1;
}
if ((entry = gnrc_ipv6_netif_get(dev)) == NULL) {
puts("error: unable to set hop limit.");
return 1;
}
entry->cur_hl = hl;
printf("success: set hop limit %u interface %" PRIkernel_pid "\n", hl, dev);
return 0;
}
#endif
else {
return _netif_flag(argv[0], dev, argv[2]);
}
}
else {
puts("error: invalid interface given");
return 1;
}
}
printf("usage: %s [<if_id>]\n", argv[0]);
_set_usage(argv[0]);
_mtu_usage(argv[0]);
_hl_usage(argv[0]);
_flag_usage(argv[0]);
_add_usage(argv[0]);
_del_usage(argv[0]);
_stats_usage(argv[0]);
return 1;
}