1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/shell/cmds/gnrc_netif.c
bors[bot] 910e0e28ed
Merge #19963 #19971 #19974 #19975 #19976
19963: sys/event/timeout: add event_timeout_is_pending() r=benpicco a=benpicco



19971: sys/shell/gnrc_netif: Fix a few blockers for sharing ifconfig shell r=benpicco a=yarrick



19974: gnrc_ipv6_ext_frag: _completed: Add comment why list head is not checked for NULL pointer dereference r=benpicco a=miri64

 


19975: pkg/nanocbor: Bump to latest commit r=benpicco a=bergzand

### Contribution description

Not much to see here

Important changes:
- Add stream-like interface for encoder
- Separate functions for number of items left in arrays and maps

### Testing procedure

The usual test should still work

### Issues/PRs references

None

19976: core: Express -1 as ~0 in thread_status_t cast r=benpicco a=SimonIT



Co-authored-by: Benjamin Valentin <benjamin.valentin@ml-pa.com>
Co-authored-by: Erik Ekman <eekman@google.com>
Co-authored-by: Martine Lenders <m.lenders@fu-berlin.de>
Co-authored-by: Koen Zandberg <koen@bergzand.net>
Co-authored-by: SimonIT <simonit.orig@gmail.com>
2023-10-16 15:31:25 +00:00

1949 lines
57 KiB
C

/*
* Copyright (C) 2017 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 interfaces
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
*/
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "fmt.h"
#include "net/gnrc.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netif/hdr.h"
#include "net/ipv6/addr.h"
#include "net/l2util.h"
#include "net/lora.h"
#include "net/loramac.h"
#include "net/netif.h"
#include "shell.h"
#ifdef MODULE_NETSTATS
#include "net/netstats.h"
#endif
#ifdef MODULE_L2FILTER
#include "net/l2filter.h"
#endif
/**
* @brief The default IPv6 prefix length if not specified.
*/
#define _IPV6_DEFAULT_PREFIX_LEN (64U)
/**
* @brief Threshold for listed option flags
*/
#define _LINE_THRESHOLD (8U)
/**
* @brief Flag command mapping
*
* @note Add options that are changed with netopt_enable_t here
*/
static const struct {
char *name;
netopt_t opt;
} flag_cmds[] = {
{ "6lo", NETOPT_6LO },
{ "ack_req", NETOPT_ACK_REQ },
{ "gts", NETOPT_GTS_TX },
{ "pan_coord", NETOPT_PAN_COORD },
{ "autoack", NETOPT_AUTOACK },
{ "autocca", NETOPT_AUTOCCA },
{ "csma", NETOPT_CSMA },
{ "encrypt", NETOPT_ENCRYPTION },
{ "mac_no_sleep", NETOPT_MAC_NO_SLEEP },
{ "fwd", NETOPT_IPV6_FORWARDING },
{ "iphc", NETOPT_6LO_IPHC },
{ "preload", NETOPT_PRELOADING },
{ "promisc", NETOPT_PROMISCUOUSMODE },
{ "phy_busy", NETOPT_PHY_BUSY },
{ "raw", NETOPT_RAWMODE },
{ "rtr_adv", NETOPT_IPV6_SND_RTR_ADV },
{ "iq_invert", NETOPT_IQ_INVERT },
{ "rx_single", NETOPT_SINGLE_RECEIVE },
{ "chan_hop", NETOPT_CHANNEL_HOP },
{ "checksum", NETOPT_CHECKSUM },
{ "otaa", NETOPT_OTAA },
{ "link_check", NETOPT_LINK_CHECK },
};
/* utility functions */
static void _print_iface_name(netif_t *iface)
{
char name[CONFIG_NETIF_NAMELENMAX];
netif_get_name(iface, name);
printf("%s", name);
}
__attribute__ ((unused))
static void str_toupper(char *str)
{
while (*str) {
*str = toupper((unsigned)*str);
++str;
}
}
__attribute__ ((unused))
static uint8_t gcd(uint8_t a, uint8_t b)
{
if (a == 0 || b == 0) {
return 0;
}
do {
uint8_t r = a % b;
a = b;
b = r;
} while (b);
return a;
}
__attribute__ ((unused))
static void frac_short(uint8_t *a, uint8_t *b)
{
uint8_t d = gcd(*a, *b);
if (d == 0) {
return;
}
*a /= d;
*b /= d;
}
__attribute__ ((unused))
static void frac_extend(uint8_t *a, uint8_t *b, uint8_t base)
{
*a *= base / *b;
*b = base;
}
#ifdef MODULE_NETSTATS
static const char *_netstats_module_to_str(uint8_t module)
{
switch (module) {
case NETSTATS_LAYER2:
return "Layer 2";
case NETSTATS_IPV6:
return "IPv6";
case NETSTATS_ALL:
return "all";
default:
return "Unknown";
}
}
static int _netif_stats(netif_t *iface, unsigned module, bool reset)
{
netstats_t stats;
int res = netif_get_opt(iface, NETOPT_STATS, module, &stats,
sizeof(stats));
if (res < 0) {
printf(" Protocol or device doesn't provide statistics.\n");
}
else if (reset) {
res = netif_set_opt(iface, NETOPT_STATS, module, NULL, 0);
printf("Reset statistics for module %s: %s!\n",
_netstats_module_to_str(module),
(res < 0) ? "failed" : "succeeded");
}
else {
printf(" Statistics for %s\n"
" RX packets %u bytes %u\n"
" TX packets %u (Multicast: %u) bytes %u\n"
" TX succeeded %u errors %u\n",
_netstats_module_to_str(module),
(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);
res = 0;
}
return res;
}
#endif /* MODULE_NETSTATS */
static void _link_usage(char *cmd_name)
{
printf("usage: %s <if_id> [up|down]\n", cmd_name);
}
static void _set_usage(char *cmd_name)
{
printf("usage: %s <if_id> set <key> <value>\n", cmd_name);
printf(" Sets a hardware 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"
" * \"cca_threshold\" - set ED threshold during CCA in dBm\n"
" * \"freq\" - sets the \"channel\" center frequency\n"
" * \"channel\" - sets the frequency channel\n"
" * \"chan\" - alias for \"channel\"\n"
" * \"checksum\" - set checksumming on-off\n"
" * \"csma_retries\" - set max. number of channel access attempts\n"
" * \"encrypt\" - set the encryption on-off\n"
" * \"hop_limit\" - set hop limit\n"
" * \"hl\" - alias for \"hop_limit\"\n"
" * \"key\" - set the encryption key in hexadecimal format\n"
" * \"mtu\" - IPv6 maximum transition unit\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"
" * \"phy_busy\" - set busy mode on-off\n"
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORA)
" * \"bw\" - alias for channel bandwidth\n"
" * \"sf\" - alias for spreading factor\n"
" * \"cr\" - alias for coding rate\n"
#endif /* MODULE_SHELL_CMD_GNRC_NETIF_LORA */
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORAWAN)
" * \"appkey\" - sets Application key\n"
" * \"appskey\" - sets Application session key\n"
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
" * \"joineui\" - sets Join EUI\n"
" * \"nwkkey\" - sets Network key\n"
" * \"nwksenckey\" - sets Network session encryption key\n"
" * \"snwksintkey\" - sets Serving network session integrity key\n"
" * \"fnwksintkey\" - sets Forwarding network session integrity key\n"
#else
" * \"appeui\" - sets Application EUI\n"
" * \"nwkskey\" - sets Network Session Key\n"
#endif
" * \"deveui\" - sets Device EUI\n"
" * \"dr\" - sets datarate\n"
" * \"rx2_dr\" - sets datarate of RX2 (lorawan)\n"
#endif
#ifdef MODULE_NETDEV_IEEE802154_MULTIMODE
" * \"phy_mode\" - select PHY mode\n"
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
" * \"chip_rate\" - BPSK/QPSK chip rate in kChip/s\n"
" * \"rate_mode\" - BPSK/QPSK rate mode\n"
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
" * \"option\" - OFDM option\n"
" * \"scheme\" - OFDM modulation & coding scheme\n"
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
" * \"modulation_index\" - FSK modulation index\n"
" * \"modulation_order\" - FSK modulation order\n"
" * \"symbol_rate\" - FSK symbol rate\n"
" * \"fec\" - FSK forward error correction\n"
" * \"channel_spacing\" - channel spacing\n"
#endif
" * \"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");
}
static void _flag_usage(char *cmd_name)
{
printf("usage: %s <if_id> [-]{", cmd_name);
for (unsigned i = 0; i < ARRAY_SIZE(flag_cmds); i++) {
printf("%s", flag_cmds[i].name);
if (i < (ARRAY_SIZE(flag_cmds) - 1)) {
printf("|");
}
}
puts("}");
}
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);
}
#ifdef MODULE_NETSTATS
static void _stats_usage(char *cmd_name)
{
printf("usage: %s <if_id> stats [l2|ipv6] [reset]\n", cmd_name);
printf(" reset can be only used if the module is specified.\n");
}
#endif
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_LORAWAN_APPKEY:
printf("AppKey");
break;
case NETOPT_LORAWAN_APPSKEY:
printf("AppSKey");
break;
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
case NETOPT_LORAWAN_JOINEUI:
printf("JoinEUI");
break;
case NETOPT_LORAWAN_NWKKEY:
printf("NwkKey");
break;
case NETOPT_LORAWAN_NWKSENCKEY:
printf("NwkSEncKey");
break;
case NETOPT_LORAWAN_SNWKSINTKEY:
printf("SNwkSIntKey");
break;
case NETOPT_LORAWAN_FNWKSINTKEY:
printf("FNwkSIntKey");
break;
#else
case NETOPT_LORAWAN_APPEUI:
printf("AppEUI");
break;
case NETOPT_LORAWAN_NWKSKEY:
printf("NwkSKey");
break;
#endif /* IS_USED(MODULE_GNRC_LORAWAN_1_1) */
case NETOPT_SRC_LEN:
printf("source address length");
break;
case NETOPT_CHANNEL:
printf("channel");
break;
case NETOPT_CHANNEL_FREQUENCY:
printf("frequency [in Hz]");
break;
case NETOPT_CHANNEL_PAGE:
printf("page");
break;
case NETOPT_HOP_LIMIT:
printf("hop limit");
break;
case NETOPT_MAX_PDU_SIZE:
printf("MTU");
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;
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORA)
case NETOPT_BANDWIDTH:
printf("bandwidth");
break;
case NETOPT_SPREADING_FACTOR:
printf("spreading factor");
break;
case NETOPT_CODING_RATE:
printf("coding rate");
break;
#endif /* MODULE_SHELL_CMD_GNRC_NETIF_LORA */
#ifdef MODULE_NETDEV_IEEE802154_MULTIMODE
case NETOPT_IEEE802154_PHY:
printf("PHY mode");
break;
#endif /* MODULE_NETDEV_IEEE802154_MULTIMODE */
#ifdef MODULE_NETDEV_IEEE802154_OQPSK
case NETOPT_OQPSK_RATE:
printf("high rate");
break;
#endif /* MODULE_NETDEV_IEEE802154_OQPSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
case NETOPT_MR_OQPSK_CHIPS:
printf("chip rate");
break;
case NETOPT_MR_OQPSK_RATE:
printf("rate mode");
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_OQPSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
case NETOPT_MR_OFDM_OPTION:
printf("OFDM option");
break;
case NETOPT_MR_OFDM_MCS:
printf("modulation/coding scheme");
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case NETOPT_MR_FSK_MODULATION_INDEX:
printf("FSK modulation index");
break;
case NETOPT_MR_FSK_MODULATION_ORDER:
printf("FSK modulation order");
break;
case NETOPT_MR_FSK_SRATE:
printf("FSK symbol rate");
break;
case NETOPT_MR_FSK_FEC:
printf("FSK Forward Error Correction");
break;
case NETOPT_CHANNEL_SPACING:
printf("Channel Spacing");
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
case NETOPT_CHECKSUM:
printf("checksum");
break;
case NETOPT_OTAA:
printf("otaa");
break;
case NETOPT_LINK_CHECK:
printf("link check");
break;
case NETOPT_PHY_BUSY:
printf("PHY busy");
break;
case NETOPT_LORAWAN_DR:
printf("datarate");
break;
case NETOPT_LORAWAN_RX2_DR:
printf("RX2 datarate");
break;
default:
/* we don't serve these options here */
break;
}
}
static const char *_netopt_state_str[] = {
[NETOPT_STATE_OFF] = "OFF",
[NETOPT_STATE_SLEEP] = "SLEEP",
[NETOPT_STATE_IDLE] = "IDLE",
[NETOPT_STATE_RX] = "RX",
[NETOPT_STATE_TX] = "TX",
[NETOPT_STATE_RESET] = "RESET",
[NETOPT_STATE_STANDBY] = "STANDBY"
};
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORA)
static const char *_netopt_bandwidth_str[] = {
[LORA_BW_125_KHZ] = "125",
[LORA_BW_250_KHZ] = "250",
[LORA_BW_500_KHZ] = "500"
};
static const char *_netopt_coding_rate_str[] = {
[LORA_CR_4_5] = "4/5",
[LORA_CR_4_6] = "4/6",
[LORA_CR_4_7] = "4/7",
[LORA_CR_4_8] = "4/8"
};
#endif /* MODULE_SHELL_CMD_GNRC_NETIF_LORA */
#ifdef MODULE_NETDEV_IEEE802154
static const char *_netopt_ieee802154_phy_str[] = {
[IEEE802154_PHY_DISABLED] = "DISABLED",
[IEEE802154_PHY_BPSK] = "BPSK",
[IEEE802154_PHY_ASK] = "ASK",
[IEEE802154_PHY_OQPSK] = "O-QPSK",
[IEEE802154_PHY_MR_OQPSK] = "MR-O-QPSK",
[IEEE802154_PHY_MR_OFDM] = "MR-OFDM",
[IEEE802154_PHY_MR_FSK] = "MR-FSK"
};
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
static const char *_netopt_ofdm_mcs_str[] = {
[0] = "BPSK, rate 1/2, 4x frequency repetition",
[1] = "BPSK, rate 1/2, 2x frequency repetition",
[2] = "QPSK, rate 1/2, 2x frequency repetition",
[3] = "QPSK, rate 1/2",
[4] = "QPSK, rate 3/4",
[5] = "16-QAM, rate 1/2",
[6] = "16-QAM, rate 3/4",
};
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
static const char *_netopt_fec_str[] = {
[IEEE802154_FEC_NONE] = "none",
[IEEE802154_FEC_NRNSC] = "NRNSC",
[IEEE802154_FEC_RSC] = "RSC"
};
#endif
/* for some lines threshold might just be 0, so we can't use _LINE_THRESHOLD
* here */
static unsigned _newline(unsigned threshold, unsigned line_thresh)
{
if (line_thresh > threshold) {
printf("\n ");
line_thresh = 0U;
}
return line_thresh;
}
static unsigned _netif_list_flag(netif_t *iface, netopt_t opt, char *str,
unsigned line_thresh)
{
netopt_enable_t enable = NETOPT_DISABLE;
int res = netif_get_opt(iface, opt, 0, &enable,
sizeof(enable));
if ((res >= 0) && (enable == NETOPT_ENABLE)) {
printf("%s", str);
line_thresh = _newline(_LINE_THRESHOLD, ++line_thresh);
}
return line_thresh;
}
#ifdef MODULE_IPV6
static void _netif_list_ipv6(ipv6_addr_t *addr, uint8_t flags)
{
char addr_str[IPV6_ADDR_MAX_STR_LEN];
printf("inet6 addr: ");
ipv6_addr_to_str(addr_str, addr, sizeof(addr_str));
printf("%s scope: ", addr_str);
if (ipv6_addr_is_link_local(addr)) {
printf("link");
}
else if (ipv6_addr_is_site_local(addr)) {
printf("site");
}
else if (ipv6_addr_is_global(addr)) {
printf("global");
}
else {
printf("unknown");
}
#if MODULE_GNRC_IPV6
if (flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_ANYCAST) {
printf(" [anycast]");
}
if (flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE) {
printf(" TNT[%u]",
flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_TENTATIVE);
}
else {
switch (flags & GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_MASK) {
case GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_DEPRECATED:
printf(" DPR");
break;
case GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID:
printf(" VAL");
break;
default:
printf(" UNK");
break;
}
}
#endif
_newline(0U, _LINE_THRESHOLD);
}
static void _netif_list_groups(ipv6_addr_t *addr)
{
if ((ipv6_addr_is_multicast(addr))) {
char addr_str[IPV6_ADDR_MAX_STR_LEN];
ipv6_addr_to_str(addr_str, addr, sizeof(addr_str));
printf("inet6 group: %s", addr_str);
}
_newline(0U, _LINE_THRESHOLD);
}
#endif
static void _netif_list(netif_t *iface)
{
#ifdef MODULE_IPV6
ipv6_addr_t ipv6_addrs[CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF];
ipv6_addr_t ipv6_groups[GNRC_NETIF_IPV6_GROUPS_NUMOF];
#endif
uint8_t hwaddr[GNRC_NETIF_L2ADDR_MAXLEN];
uint32_t u32;
uint16_t u16;
int16_t i16;
uint8_t u8;
int res;
netopt_state_t state;
unsigned line_thresh = 1;
printf("Iface ");
_print_iface_name(iface);
printf(" ");
/* XXX divide options and flags by at least two spaces! */
res = netif_get_opt(iface, NETOPT_ADDRESS, 0, hwaddr, sizeof(hwaddr));
if (res >= 0) {
char hwaddr_str[res * 3];
printf(" HWaddr: %s ",
l2util_addr_to_str(hwaddr, res, hwaddr_str));
}
res = netif_get_opt(iface, NETOPT_CHANNEL, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" Channel: %" PRIu16 " ", u16);
}
res = netif_get_opt(iface, NETOPT_CHANNEL_FREQUENCY, 0, &u32, sizeof(u32));
if (res >= 0) {
printf(" Frequency: %" PRIu32 "Hz ", u32);
}
res = netif_get_opt(iface, NETOPT_CHANNEL_PAGE, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" Page: %" PRIu16 " ", u16);
}
res = netif_get_opt(iface, NETOPT_NID, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" NID: 0x%" PRIx16 " ", u16);
}
res = netif_get_opt(iface, NETOPT_RSSI, 0, &i16, sizeof(i16));
if (res >= 0) {
printf(" RSSI: %d ", i16);
}
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORA)
res = netif_get_opt(iface, NETOPT_BANDWIDTH, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" BW: %skHz ", _netopt_bandwidth_str[u8]);
}
res = netif_get_opt(iface, NETOPT_SPREADING_FACTOR, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" SF: %u ", u8);
}
res = netif_get_opt(iface, NETOPT_CODING_RATE, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" CR: %s ", _netopt_coding_rate_str[u8]);
}
#endif /* MODULE_SHELL_CMD_GNRC_NETIF_LORA */
#ifdef MODULE_NETDEV_IEEE802154
res = netif_get_opt(iface, NETOPT_IEEE802154_PHY, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" PHY: %s ", _netopt_ieee802154_phy_str[u8]);
switch (u8) {
#ifdef MODULE_NETDEV_IEEE802154_OQPSK
case IEEE802154_PHY_OQPSK:
printf("\n ");
res = netif_get_opt(iface, NETOPT_OQPSK_RATE, 0, &u8, sizeof(u8));
if (res >= 0 && u8) {
printf(" high data rate: %d ", u8);
}
break;
#endif /* MODULE_NETDEV_IEEE802154_OQPSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
case IEEE802154_PHY_MR_OQPSK:
printf("\n ");
res = netif_get_opt(iface, NETOPT_MR_OQPSK_CHIPS, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" chip rate: %u ", u16);
}
res = netif_get_opt(iface, NETOPT_MR_OQPSK_RATE, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" rate mode: %d ", u8);
}
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_OQPSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
case IEEE802154_PHY_MR_OFDM:
printf("\n ");
res = netif_get_opt(iface, NETOPT_MR_OFDM_OPTION, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" Option: %u ", u8);
}
res = netif_get_opt(iface, NETOPT_MR_OFDM_MCS, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" MCS: %u (%s) ", u8, _netopt_ofdm_mcs_str[u8]);
}
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case IEEE802154_PHY_MR_FSK:
printf("\n ");
res = netif_get_opt(iface, NETOPT_MR_FSK_MODULATION_INDEX, 0, &u8, sizeof(u8));
if (res >= 0) {
hwaddr[0] = 64; /* convenient temp var */
frac_short(&u8, hwaddr);
if (hwaddr[0] == 1) {
printf(" modulation index: %u ", u8);
}
else {
printf(" modulation index: %u/%u ", u8, hwaddr[0]);
}
}
res = netif_get_opt(iface, NETOPT_MR_FSK_MODULATION_ORDER, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" %u-FSK ", u8);
}
res = netif_get_opt(iface, NETOPT_MR_FSK_SRATE, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" symbol rate: %u kHz ", u16);
}
res = netif_get_opt(iface, NETOPT_MR_FSK_FEC, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" FEC: %s ", _netopt_fec_str[u8]);
}
res = netif_get_opt(iface, NETOPT_CHANNEL_SPACING, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" BW: %ukHz ", u16);
}
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
}
}
#endif /* MODULE_NETDEV_IEEE802154 */
netopt_enable_t enabled;
res = netif_get_opt(iface, NETOPT_LINK, 0, &enabled, sizeof(enabled));
if (res >= 0) {
printf(" Link: %s ", (enabled == NETOPT_ENABLE) ? "up" : "down" );
}
#if IS_USED(MODULE_LWIP_NETIF) /* only supported on lwIP for now */
res = netif_get_opt(iface, NETOPT_ACTIVE, 0, &enabled, sizeof(enabled));
if (res >= 0) {
printf(" State: %s ", (enabled == NETOPT_ENABLE) ? "up" : "down" );
}
#endif /* MODULE_LWIP_NETIF */
line_thresh = _newline(0U, line_thresh);
res = netif_get_opt(iface, NETOPT_ADDRESS_LONG, 0, hwaddr, sizeof(hwaddr));
if (res >= 0) {
char hwaddr_str[res * 3];
printf("Long HWaddr: ");
printf("%s ", l2util_addr_to_str(hwaddr, res, hwaddr_str));
line_thresh++;
}
line_thresh = _newline(0U, line_thresh);
res = netif_get_opt(iface, NETOPT_TX_POWER, 0, &i16, sizeof(i16));
if (res >= 0) {
printf(" TX-Power: %" PRIi16 "dBm ", i16);
}
res = netif_get_opt(iface, NETOPT_STATE, 0, &state, sizeof(state));
if (res >= 0) {
printf(" State: %s ", _netopt_state_str[state]);
line_thresh++;
}
res = netif_get_opt(iface, NETOPT_RETRANS, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" max. Retrans.: %u ", (unsigned)u8);
line_thresh++;
}
res = netif_get_opt(iface, NETOPT_CSMA_RETRIES, 0, &u8, sizeof(u8));
if (res >= 0) {
enabled = NETOPT_DISABLE;
res = netif_get_opt(iface, NETOPT_CSMA, 0, &enabled, sizeof(enabled));
if ((res >= 0) && (enabled == NETOPT_ENABLE)) {
printf(" CSMA Retries: %u ", (unsigned)u8);
}
line_thresh++;
}
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORAWAN)
res = netif_get_opt(iface, NETOPT_DEMOD_MARGIN, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" Demod margin.: %u ", (unsigned)u8);
line_thresh++;
}
res = netif_get_opt(iface, NETOPT_NUM_GATEWAYS, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" Num gateways.: %u ", (unsigned)u8);
line_thresh++;
}
#endif
/* XXX divide options and flags by at least two spaces! */
line_thresh = _newline(0U, line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_PROMISCUOUSMODE, "PROMISC ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_AUTOACK, "AUTOACK ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_ACK_REQ, "ACK_REQ ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_PRELOADING, "PRELOAD ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_RAWMODE, "RAWMODE ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_MAC_NO_SLEEP, "MAC_NO_SLEEP ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_CSMA, "CSMA ",
line_thresh);
line_thresh += _LINE_THRESHOLD + 1; /* enforce linebreak after this option */
line_thresh = _netif_list_flag(iface, NETOPT_AUTOCCA, "AUTOCCA ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_IQ_INVERT, "IQ_INVERT ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_SINGLE_RECEIVE, "RX_SINGLE ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_CHANNEL_HOP, "CHAN_HOP ",
line_thresh);
line_thresh = _netif_list_flag(iface, NETOPT_OTAA, "OTAA ",
line_thresh);
/* XXX divide options and flags by at least two spaces! */
res = netif_get_opt(iface, NETOPT_MAX_PDU_SIZE, 0, &u16, sizeof(u16));
if (res > 0) {
printf("L2-PDU:%" PRIu16 " ", u16);
line_thresh++;
}
#ifdef MODULE_GNRC_IPV6
res = netif_get_opt(iface, NETOPT_MAX_PDU_SIZE, GNRC_NETTYPE_IPV6, &u16, sizeof(u16));
if (res > 0) {
printf("MTU:%" PRIu16 " ", u16);
line_thresh++;
}
res = netif_get_opt(iface, NETOPT_HOP_LIMIT, 0, &u8, sizeof(u8));
if (res > 0) {
printf("HL:%u ", u8);
line_thresh++;
}
line_thresh = _netif_list_flag(iface, NETOPT_IPV6_FORWARDING, "RTR ",
line_thresh);
#ifndef MODULE_GNRC_SIXLOWPAN_IPHC
line_thresh += _LINE_THRESHOLD + 1; /* enforce linebreak after this option */
#endif
line_thresh = _netif_list_flag(iface, NETOPT_IPV6_SND_RTR_ADV, "RTR_ADV ",
line_thresh);
#ifdef MODULE_GNRC_SIXLOWPAN
line_thresh = _netif_list_flag(iface, NETOPT_6LO, "6LO ", line_thresh);
#endif
#ifdef MODULE_GNRC_SIXLOWPAN_IPHC
line_thresh += _LINE_THRESHOLD + 1; /* enforce linebreak after this option */
line_thresh = _netif_list_flag(iface, NETOPT_6LO_IPHC, "IPHC ",
line_thresh);
#endif
#endif
res = netif_get_opt(iface, NETOPT_SRC_LEN, 0, &u16, sizeof(u16));
/* XXX divide options and flags by at least two spaces before this line! */
if (res >= 0) {
printf("Source address length: %" PRIu16, u16);
line_thresh++;
}
line_thresh = _newline(0U, line_thresh);
printf("Link type: %s",
(netif_get_opt(iface, NETOPT_IS_WIRED, 0, &u16, sizeof(u16)) > 0) ?
"wired" : "wireless");
_newline(0U, ++line_thresh);
#ifdef MODULE_IPV6
res = netif_get_opt(iface, NETOPT_IPV6_ADDR, 0, ipv6_addrs,
sizeof(ipv6_addrs));
if (res >= 0) {
uint8_t ipv6_addrs_flags[CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF];
memset(ipv6_addrs_flags, 0, sizeof(ipv6_addrs_flags));
/* assume it to succeed (otherwise array will stay 0) */
netif_get_opt(iface, NETOPT_IPV6_ADDR_FLAGS, 0, ipv6_addrs_flags,
sizeof(ipv6_addrs_flags));
/* yes, the res of NETOPT_IPV6_ADDR is meant to be here ;-) */
for (unsigned i = 0; i < (res / sizeof(ipv6_addr_t)); i++) {
_netif_list_ipv6(&ipv6_addrs[i], ipv6_addrs_flags[i]);
}
}
res = netif_get_opt(iface, NETOPT_IPV6_GROUP, 0, ipv6_groups,
sizeof(ipv6_groups));
if (res >= 0) {
for (unsigned i = 0; i < (res / sizeof(ipv6_addr_t)); i++) {
_netif_list_groups(&ipv6_groups[i]);
}
}
#endif
#ifdef MODULE_L2FILTER
l2filter_t *filter = NULL;
res = netif_get_opt(iface, NETOPT_L2FILTER, 0, &filter, sizeof(filter));
if (res > 0) {
#ifdef MODULE_L2FILTER_WHITELIST
printf("\n White-listed link layer addresses:\n");
#else
printf("\n Black-listed link layer addresses:\n");
#endif
int count = 0;
for (unsigned i = 0; i < CONFIG_L2FILTER_LISTSIZE; i++) {
if (filter[i].addr_len > 0) {
char hwaddr_str[filter[i].addr_len * 3];
l2util_addr_to_str(filter[i].addr, filter[i].addr_len,
hwaddr_str);
printf(" %2i: %s\n", count++, hwaddr_str);
}
}
if (count == 0) {
printf(" --- none ---\n");
}
}
#endif
#ifdef MODULE_NETSTATS_L2
puts("");
_netif_stats(iface, NETSTATS_LAYER2, false);
#endif
#ifdef MODULE_NETSTATS_IPV6
_netif_stats(iface, NETSTATS_IPV6, false);
#endif
puts("");
}
static int _netif_set_u32(netif_t *iface, netopt_t opt, uint32_t context,
char *u32_str)
{
unsigned long int res;
bool hex = false;
if (fmt_is_number(u32_str)) {
if ((res = strtoul(u32_str, NULL, 10)) == ULONG_MAX) {
printf("error: unable to parse value.\n"
"Must be a 32-bit unsigned integer (dec or hex)\n");
return 1;
}
}
else {
if ((res = strtoul(u32_str, NULL, 32)) == ULONG_MAX) {
printf("error: unable to parse value.\n"
"Must be a 32-bit unsigned integer (dec or hex)\n");
return 1;
}
hex = true;
}
assert(res <= ULONG_MAX);
if (netif_set_opt(iface, opt, context, (uint32_t *)&res,
sizeof(uint32_t)) < 0) {
printf("error: unable to set ");
_print_netopt(opt);
puts("");
return 1;
}
printf("success: set ");
_print_netopt(opt);
printf(" on interface ");
_print_iface_name(iface);
printf(" to ");
if (hex) {
printf("0x%04lx\n", res);
}
else {
printf("%lu\n", res);
}
return 0;
}
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORA)
static int _netif_set_bandwidth(netif_t *iface, char *value)
{
uint8_t bw;
if (strcmp("125", value) == 0) {
bw = LORA_BW_125_KHZ;
}
else if (strcmp("250", value) == 0) {
bw = LORA_BW_250_KHZ;
}
else if (strcmp("500", value) == 0) {
bw = LORA_BW_500_KHZ;
}
else {
printf("usage: ifconfig <if_id> set bw [125|250|500]\n");
return 1;
}
if (netif_set_opt(iface, NETOPT_BANDWIDTH, 0,
&bw, sizeof(uint8_t)) < 0) {
printf("error: unable to set bandwidth to %s\n", value);
return 1;
}
printf("success: set bandwidth of interface ");
_print_iface_name(iface);
printf(" to %s\n", value);
return 0;
}
static int _netif_set_coding_rate(netif_t *iface, char *value)
{
uint8_t cr;
if (strcmp("4/5", value) == 0) {
cr = LORA_CR_4_5;
}
else if (strcmp("4/6", value) == 0) {
cr = LORA_CR_4_6;
}
else if (strcmp("4/7", value) == 0) {
cr = LORA_CR_4_7;
}
else if (strcmp("4/8", value) == 0) {
cr = LORA_CR_4_8;
}
else {
printf("usage: ifconfig <if_id> set cr [4/5|4/6|4/7|4/8]\n");
return 1;
}
if (netif_set_opt(iface, NETOPT_CODING_RATE, 0,
&cr, sizeof(uint8_t)) < 0) {
printf("error: unable to set coding rate to %s\n", value);
return 1;
}
printf("success: set coding rate of interface ");
_print_iface_name(iface);
printf(" to %s\n", value);
return 0;
}
#endif /* MODULE_SHELL_CMD_GNRC_NETIF_LORA */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
static int _netif_set_fsk_fec(netif_t *iface, char *value)
{
/* ignore case */
str_toupper(value);
for (size_t i = 0; i < ARRAY_SIZE(_netopt_fec_str); ++i) {
if (strcmp(value, _netopt_fec_str[i])) {
continue;
}
if (netif_set_opt(iface, NETOPT_MR_FSK_FEC, 0, &i, sizeof(uint8_t)) < 0) {
printf("error: unable to set forward error correction to %s\n", value);
return 1;
}
printf("success: set forward error correction to %s\n", value);
return 0;
}
printf("usage: ifconfig <if_id> set fec [none|NRNSC|RSC]\n");
return 1;
}
static int _netif_set_fsk_modulation_index(netif_t *iface, char *value)
{
uint8_t a, b;
char *frac = strchr(value, '/');
if (frac) {
*frac = 0;
b = atoi(frac + 1);
}
else {
b = 1;
}
a = atoi(value);
frac_extend(&a, &b, 64);
int res = netif_set_opt(iface, NETOPT_MR_FSK_MODULATION_INDEX, 0, &a, sizeof(uint8_t));
if (res < 0) {
printf("error: unable to set modulation index to %d/%d\n", a, b);
return 1;
}
else {
printf("success: set modulation index to %d/%d\n", res, b);
}
return 0;
}
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
#ifdef MODULE_NETDEV_IEEE802154_MULTIMODE
static int _netif_set_ieee802154_phy_mode(netif_t *iface, char *value)
{
/* ignore case */
str_toupper(value);
for (uint8_t i = 0; i < ARRAY_SIZE(_netopt_ieee802154_phy_str); ++i) {
if (strcmp(_netopt_ieee802154_phy_str[i], value)) {
continue;
}
if (netif_set_opt(iface, NETOPT_IEEE802154_PHY, 0, &i, sizeof(uint8_t)) < 0) {
printf("error: unable to set PHY mode to %s\n", value);
return 1;
}
printf("success: set PHY mode %s\n", value);
return 0;
}
printf("usage: ifconfig <if_id> set phy ");
for (unsigned i = 0; i < ARRAY_SIZE(_netopt_ieee802154_phy_str); ++i) {
printf("%c%s", i ? '|' : '[', _netopt_ieee802154_phy_str[i]);
}
puts("]");
return 1;
}
#endif /* MODULE_NETDEV_IEEE802154_MULTIMODE */
static int _netif_set_u16(netif_t *iface, netopt_t opt, uint16_t context,
char *u16_str)
{
unsigned long int res;
bool hex = false;
if (fmt_is_number(u16_str)) {
if ((res = strtoul(u16_str, NULL, 10)) == ULONG_MAX) {
printf("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) {
printf("error: unable to parse value.\n"
"Must be a 16-bit unsigned integer (dec or hex)\n");
return 1;
}
hex = true;
}
if (res > 0xffff) {
printf("error: unable to parse value.\n"
"Must be a 16-bit unsigned integer (dec or hex)\n");
return 1;
}
if (netif_set_opt(iface, opt, context, (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 ");
_print_iface_name(iface);
printf(" to ");
if (hex) {
printf("0x%04lx\n", res);
}
else {
printf("%lu\n", res);
}
return 0;
}
static int _netif_set_i16(netif_t *iface, netopt_t opt, char *i16_str)
{
int16_t val = atoi(i16_str);
if (netif_set_opt(iface, 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 ");
_print_iface_name(iface);
printf(" to %i\n", val);
return 0;
}
static int _netif_set_u8(netif_t *iface, netopt_t opt, uint16_t context,
char *u8_str)
{
uint8_t val = atoi(u8_str);
if (netif_set_opt(iface, opt, context, (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 ");
_print_iface_name(iface);
printf(" to %i\n", val);
return 0;
}
static int _netif_set_flag(netif_t *iface, netopt_t opt, netopt_enable_t set)
{
if (netif_set_opt(iface, opt, 0, &set, sizeof(netopt_enable_t)) < 0) {
printf("error: unable to set option\n");
return 1;
}
printf("success: %sset option\n", (set) ? "" : "un");
return 0;
}
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORAWAN)
static int _netif_set_lw_key(netif_t *iface, netopt_t opt, char *key_str)
{
/* This is the longest key */
uint8_t key[LORAMAC_APPKEY_LEN];
size_t key_len = fmt_hex_bytes(key, key_str);
size_t expected_len;
switch (opt) {
case NETOPT_LORAWAN_APPKEY:
case NETOPT_LORAWAN_APPSKEY:
case NETOPT_LORAWAN_NWKSKEY:
case NETOPT_LORAWAN_NWKKEY:
case NETOPT_LORAWAN_SNWKSINTKEY:
case NETOPT_LORAWAN_FNWKSINTKEY:
case NETOPT_LORAWAN_NWKSENCKEY:
/* All keys have the same length as the APP KEY */
expected_len = LORAMAC_APPKEY_LEN;
break;
default:
/* Same rationale here */
expected_len = LORAMAC_DEVEUI_LEN;
}
if (!key_len || key_len != expected_len) {
printf("error: unable to parse key.\n");
return 1;
}
netif_set_opt(iface, opt, 0, &key, expected_len);
printf("success: set ");
_print_netopt(opt);
printf(" on interface ");
_print_iface_name(iface);
printf(" to %s\n", key_str);
return 0;
}
#endif
static int _netif_set_addr(netif_t *iface, netopt_t opt, char *addr_str)
{
uint8_t addr[GNRC_NETIF_L2ADDR_MAXLEN];
size_t addr_len = l2util_addr_from_str(addr_str, addr);
if (addr_len == 0) {
printf("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)\n");
return 1;
}
if (netif_set_opt(iface, 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 ");
_print_iface_name(iface);
printf(" to %s\n", addr_str);
return 0;
}
static int _netif_set_state(netif_t *iface, 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("rx", state_str) == 0) ||
(strcmp("RX", state_str) == 0)) {
state = NETOPT_STATE_RX;
}
else if ((strcmp("tx", state_str) == 0) ||
(strcmp("TX", state_str) == 0)) {
state = NETOPT_STATE_TX;
}
else if ((strcmp("reset", state_str) == 0) ||
(strcmp("RESET", state_str) == 0)) {
state = NETOPT_STATE_RESET;
}
else if ((strcmp("standby", state_str) == 0) ||
(strcmp("STANDBY", state_str) == 0)) {
state = NETOPT_STATE_STANDBY;
}
else {
printf("usage: ifconfig <if_id> set state [off|sleep|idle|rx|tx|reset|standby]\n");
return 1;
}
if (netif_set_opt(iface, NETOPT_STATE, 0,
&state, sizeof(netopt_state_t)) < 0) {
printf("error: unable to set state to %s\n", _netopt_state_str[state]);
return 1;
}
printf("success: set state of interface ");
_print_iface_name(iface);
printf(" to %s\n", _netopt_state_str[state]);
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(netif_t *iface, 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) {
printf("error: unable to parse key\n");
return 1;
}
key[i / 2] = (uint8_t)((i1 << 4) + i2);
}
if (netif_set_opt(iface, opt, 0, key, key_len) < 0) {
printf("error: unable to set encryption key\n");
return 1;
}
printf("success: set encryption key on interface ");
_print_iface_name(iface);
printf(" to \n");
for (size_t i = 0; i < key_len; i++) {
/* print the hex value of the key */
printf("%02x", key[i]);
}
puts("");
return 0;
}
#ifdef MODULE_L2FILTER
static int _netif_addrm_l2filter(netif_t *iface, char *val, bool add)
{
uint8_t addr[GNRC_NETIF_L2ADDR_MAXLEN];
size_t addr_len = l2util_addr_from_str(val, addr);
if ((addr_len == 0) || (addr_len > CONFIG_L2FILTER_ADDR_MAXLEN)) {
printf("error: given address is invalid\n");
return 1;
}
if (add) {
if (netif_set_opt(iface, NETOPT_L2FILTER, 0, addr, addr_len) < 0) {
printf("unable to add link layer address to filter\n");
return 1;
}
printf("successfully added address to filter\n");
}
else {
if (netif_set_opt(iface, NETOPT_L2FILTER_RM, 0, addr, addr_len) < 0) {
printf("unable to remove link layer address from filter\n");
return 1;
}
printf("successfully removed address to filter\n");
}
return 0;
}
static void _l2filter_usage(const char *cmd)
{
printf("usage: %s <if_id> l2filter {add|del} <addr>\n", cmd);
}
#endif
static void _usage(char *cmd)
{
printf("usage: %s\n", cmd);
printf("usage: %s help\n", cmd);
_link_usage(cmd);
_set_usage(cmd);
_flag_usage(cmd);
_add_usage(cmd);
_del_usage(cmd);
#ifdef MODULE_L2FILTER
_l2filter_usage(cmd);
#endif
#ifdef MODULE_NETSTATS
_stats_usage(cmd);
#endif
}
static int _netif_set(char *cmd_name, netif_t *iface, char *key, char *value)
{
if ((strcmp("addr", key) == 0) || (strcmp("addr_short", key) == 0)) {
return _netif_set_addr(iface, NETOPT_ADDRESS, value);
}
else if (strcmp("addr_long", key) == 0) {
return _netif_set_addr(iface, NETOPT_ADDRESS_LONG, value);
}
else if (strcmp("cca_threshold", key) == 0) {
return _netif_set_u8(iface, NETOPT_CCA_THRESHOLD, 0, value);
}
else if ((strcmp("frequency", key) == 0) || (strcmp("freq", key) == 0)) {
return _netif_set_u32(iface, NETOPT_CHANNEL_FREQUENCY, 0, value);
}
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORA)
else if ((strcmp("bandwidth", key) == 0) || (strcmp("bw", key) == 0)) {
return _netif_set_bandwidth(iface, value);
}
else if ((strcmp("spreading_factor", key) == 0) || (strcmp("sf", key) == 0)) {
return _netif_set_u8(iface, NETOPT_SPREADING_FACTOR, 0, value);
}
else if ((strcmp("coding_rate", key) == 0) || (strcmp("cr", key) == 0)) {
return _netif_set_coding_rate(iface, value);
}
#endif /* MODULE_SHELL_CMD_GNRC_NETIF_LORA */
#if IS_USED(MODULE_SHELL_CMD_GNRC_NETIF_LORAWAN)
#if IS_USED(MODULE_GNRC_LORAWAN_1_1)
else if (strcmp("joineui", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_JOINEUI, value);
}
else if (strcmp("fnwksintkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_FNWKSINTKEY, value);
}
else if (strcmp("snwksintkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_SNWKSINTKEY, value);
}
else if (strcmp("nwksenckey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_NWKSENCKEY, value);
}
else if (strcmp("nwkkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_NWKKEY, value);
}
#else
else if (strcmp("appeui", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_APPEUI, value);
}
else if (strcmp("nwkskey", key) == 0) {
return _netif_set_addr(iface, NETOPT_LORAWAN_NWKSKEY, value);
}
#endif /* IS_USED(MODULE_GNRC_LORAWAN_1_1) */
else if (strcmp("appskey", key) == 0) {
return _netif_set_addr(iface, NETOPT_LORAWAN_APPSKEY, value);
}
else if (strcmp("appkey", key) == 0) {
return _netif_set_lw_key(iface, NETOPT_LORAWAN_APPKEY, value);
}
else if (strcmp("deveui", key) == 0) {
return _netif_set_addr(iface, NETOPT_ADDRESS_LONG, value);
}
else if (strcmp("dr", key) == 0) {
return _netif_set_u8(iface, NETOPT_LORAWAN_DR, 0, value);
}
else if (strcmp("rx2_dr", key) == 0) {
return _netif_set_u8(iface, NETOPT_LORAWAN_RX2_DR, 0, value);
}
#endif /* MODULE_SHELL_CMD_GNRC_NETIF_LORAWAN */
#ifdef MODULE_NETDEV_IEEE802154_MULTIMODE
else if ((strcmp("phy_mode", key) == 0) || (strcmp("phy", key) == 0)) {
return _netif_set_ieee802154_phy_mode(iface, value);
}
#endif /* MODULE_NETDEV_IEEE802154_MULTIMODE */
#ifdef MODULE_NETDEV_IEEE802154_OQPSK
else if (strcmp("high_rate", key) == 0) {
return _netif_set_u8(iface, NETOPT_OQPSK_RATE, 0, value);
}
#endif /* MODULE_NETDEV_IEEE802154_OQPSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
else if ((strcmp("chip_rate", key) == 0) || (strcmp("chips", key) == 0)) {
return _netif_set_u16(iface, NETOPT_MR_OQPSK_CHIPS, 0, value);
}
else if (strcmp("rate_mode", key) == 0) {
return _netif_set_u8(iface, NETOPT_MR_OQPSK_RATE, 0, value);
}
#endif /* MODULE_NETDEV_IEEE802154_MR_OQPSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
else if ((strcmp("option", key) == 0) || (strcmp("opt", key) == 0)) {
return _netif_set_u8(iface, NETOPT_MR_OFDM_OPTION, 0, value);
}
else if ((strcmp("scheme", key) == 0) || (strcmp("mcs", key) == 0)) {
return _netif_set_u8(iface, NETOPT_MR_OFDM_MCS, 0, value);
}
#endif /* MODULE_NETDEV_IEEE802154_MR_OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
else if ((strcmp("modulation_index", key) == 0) || (strcmp("midx", key) == 0)) {
return _netif_set_fsk_modulation_index(iface, value);
}
else if ((strcmp("modulation_order", key) == 0) || (strcmp("mord", key) == 0)) {
return _netif_set_u8(iface, NETOPT_MR_FSK_MODULATION_ORDER, 0, value);
}
else if ((strcmp("symbol_rate", key) == 0) || (strcmp("srate", key) == 0)) {
return _netif_set_u16(iface, NETOPT_MR_FSK_SRATE, 0, value);
}
else if ((strcmp("forward_error_correction", key) == 0) || (strcmp("fec", key) == 0)) {
return _netif_set_fsk_fec(iface, value);
}
else if ((strcmp("channel_spacing", key) == 0) || (strcmp("bw", key) == 0)) {
return _netif_set_u16(iface, NETOPT_CHANNEL_SPACING, 0, value);
}
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
else if ((strcmp("channel", key) == 0) || (strcmp("chan", key) == 0)) {
return _netif_set_u16(iface, NETOPT_CHANNEL, 0, value);
}
else if (strcmp("csma_retries", key) == 0) {
return _netif_set_u8(iface, NETOPT_CSMA_RETRIES, 0, value);
}
else if ((strcmp("hl", key) == 0) || (strcmp("hop_limit", key) == 0)) {
return _netif_set_u8(iface, NETOPT_HOP_LIMIT, 0, value);
}
else if (strcmp("key", key) == 0) {
return _netif_set_encrypt_key(iface, NETOPT_ENCRYPTION_KEY, value);
}
#ifdef MODULE_GNRC_IPV6
else if (strcmp("mtu", key) == 0) {
return _netif_set_u16(iface, NETOPT_MAX_PDU_SIZE, GNRC_NETTYPE_IPV6,
value);
}
#endif
else if ((strcmp("nid", key) == 0) || (strcmp("pan", key) == 0) ||
(strcmp("pan_id", key) == 0)) {
return _netif_set_u16(iface, NETOPT_NID, 0, value);
}
else if (strcmp("page", key) == 0) {
return _netif_set_u16(iface, NETOPT_CHANNEL_PAGE, 0, value);
}
else if (strcmp("power", key) == 0) {
return _netif_set_i16(iface, NETOPT_TX_POWER, value);
}
else if (strcmp("retrans", key) == 0) {
return _netif_set_u8(iface, NETOPT_RETRANS, 0, value);
}
else if (strcmp("src_len", key) == 0) {
return _netif_set_u16(iface, NETOPT_SRC_LEN, 0, value);
}
else if (strcmp("state", key) == 0) {
return _netif_set_state(iface, value);
}
_set_usage(cmd_name);
return 1;
}
static int _netif_flag(char *cmd, netif_t *iface, char *flag)
{
netopt_enable_t set = NETOPT_ENABLE;
if (flag[0] == '-') {
set = NETOPT_DISABLE;
flag++;
}
for (unsigned i = 0; i < ARRAY_SIZE(flag_cmds); i++) {
if (strcmp(flag_cmds[i].name, flag) == 0) {
return _netif_set_flag(iface, flag_cmds[i].opt, set);
}
}
_flag_usage(cmd);
return 1;
}
#ifdef MODULE_GNRC_IPV6
static uint8_t _get_prefix_len(char *addr)
{
int prefix_len = ipv6_addr_split_int(addr, '/', _IPV6_DEFAULT_PREFIX_LEN);
if (prefix_len < 1) {
prefix_len = _IPV6_DEFAULT_PREFIX_LEN;
}
return prefix_len;
}
#endif
static int _netif_link(netif_t *iface, netopt_enable_t en)
{
#if IS_USED(MODULE_LWIP_NETIF) /* lwIP sets netif state, not link state */
if (netif_set_opt(iface, NETOPT_ACTIVE, 0, &en, sizeof(en)) < 0) {
printf("error: unable to set state %s\n", en == NETOPT_ENABLE ? "up" : "down");
return 1;
}
#else
if (netif_set_opt(iface, NETOPT_LINK, 0, &en, sizeof(en)) < 0) {
printf("error: unable to set link %s\n", en == NETOPT_ENABLE ? "up" : "down");
return 1;
}
#endif
return 0;
}
static int _netif_add(char *cmd_name, netif_t *iface, int argc, char **argv)
{
#ifdef MODULE_GNRC_IPV6
enum {
_UNICAST = 0,
_ANYCAST
} type = _UNICAST;
char *addr_str = argv[0];
ipv6_addr_t addr;
uint16_t flags = GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_VALID;
uint8_t prefix_len;
if (argc > 1) {
if (strcmp(argv[0], "anycast") == 0) {
type = _ANYCAST;
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) {
printf("error: unable to parse IPv6 address.\n");
return 1;
}
if (ipv6_addr_is_multicast(&addr)) {
if (netif_set_opt(iface, NETOPT_IPV6_GROUP, 0, &addr,
sizeof(addr)) < 0) {
printf("error: unable to join IPv6 multicast group\n");
return 1;
}
}
else {
if (type == _ANYCAST) {
flags |= GNRC_NETIF_IPV6_ADDRS_FLAGS_ANYCAST;
}
flags |= (prefix_len << 8U);
if (netif_set_opt(iface, NETOPT_IPV6_ADDR, flags, &addr,
sizeof(addr)) < 0) {
printf("error: unable to add IPv6 address\n");
return 1;
}
}
printf("success: added %s/%d to interface ", addr_str, prefix_len);
_print_iface_name(iface);
printf("\n");
return 0;
#else
(void)cmd_name;
(void)iface;
(void)argc;
(void)argv;
printf("error: unable to add IPv6 address.\n");
return 1;
#endif
}
static int _netif_del(netif_t *iface, char *addr_str)
{
#ifdef MODULE_GNRC_IPV6
ipv6_addr_t addr;
if (ipv6_addr_from_str(&addr, addr_str) == NULL) {
printf("error: unable to parse IPv6 address.\n");
return 1;
}
if (ipv6_addr_is_multicast(&addr)) {
if (netif_set_opt(iface, NETOPT_IPV6_GROUP_LEAVE, 0, &addr,
sizeof(addr)) < 0) {
printf("error: unable to leave IPv6 multicast group\n");
return 1;
}
}
else {
if (netif_set_opt(iface, NETOPT_IPV6_ADDR_REMOVE, 0, &addr,
sizeof(addr)) < 0) {
printf("error: unable to remove IPv6 address\n");
return 1;
}
}
printf("success: removed %s to interface ", addr_str);
_print_iface_name(iface);
printf("\n");
return 0;
#else
(void)iface;
(void)addr_str;
printf("error: unable to delete IPv6 address.\n");
return 1;
#endif
}
/* shell commands */
/* TODO: updated tests/net/gnrc_dhcpv6_client to no longer abuse this shell command
* and add static qualifier */
int _gnrc_netif_config(int argc, char **argv)
{
if (argc < 2) {
netif_t *last = NULL;
/* Get interfaces in reverse order since the list is used like a stack.
* Stop when first netif in list already has been listed. */
while (last != netif_iter(NULL)) {
netif_t *netif = NULL;
netif_t *next = netif_iter(netif);
/* Step until next is end of list or was previously listed. */
do {
netif = next;
next = netif_iter(netif);
} while (next && next != last);
_netif_list(netif);
last = netif;
}
return 0;
}
else {
netif_t *iface = netif_get_by_name(argv[1]);
if (!iface) {
if ((strcmp(argv[1], "help") == 0) ||
(strcmp(argv[1], "--help") == 0)) {
_usage(argv[0]);
return 0;
}
else {
printf("error: invalid interface given\n");
return 1;
}
}
if (argc < 3) {
_netif_list(iface);
return 0;
}
else if (strcmp(argv[2], "set") == 0) {
if (argc < 5) {
_set_usage(argv[0]);
return 1;
}
return _netif_set(argv[0], iface, argv[3], argv[4]);
}
else if (strcmp(argv[2], "up") == 0) {
return _netif_link(iface, NETOPT_ENABLE);
}
else if (strcmp(argv[2], "down") == 0) {
return _netif_link(iface, NETOPT_DISABLE);
}
else if (strcmp(argv[2], "add") == 0) {
if (argc < 4) {
_add_usage(argv[0]);
return 1;
}
return _netif_add(argv[0], iface, argc - 3, argv + 3);
}
else if (strcmp(argv[2], "del") == 0) {
if (argc < 4) {
_del_usage(argv[0]);
return 1;
}
return _netif_del(iface, argv[3]);
}
#ifdef MODULE_L2FILTER
else if (strcmp(argv[2], "l2filter") == 0) {
if (argc < 5) {
_l2filter_usage(argv[2]);
}
else if (strcmp(argv[3], "add") == 0) {
return _netif_addrm_l2filter(iface, argv[4], true);
}
else if (strcmp(argv[3], "del") == 0) {
return _netif_addrm_l2filter(iface, argv[4], false);
}
else {
_l2filter_usage(argv[2]);
}
return 1;
}
#endif
#ifdef MODULE_NETSTATS
else if (strcmp(argv[2], "stats") == 0) {
uint8_t module;
bool reset = false;
/* check for requested module */
if ((argc == 3) || (strcmp(argv[3], "all") == 0)) {
module = NETSTATS_ALL;
}
else if (strcmp(argv[3], "l2") == 0) {
module = NETSTATS_LAYER2;
}
else if (strcmp(argv[3], "ipv6") == 0) {
module = NETSTATS_IPV6;
}
else {
printf("Module %s doesn't exist or does not provide statistics.\n", argv[3]);
return 0;
}
/* check if reset flag was given */
if ((argc > 4) && (strncmp(argv[4], "reset", 5) == 0)) {
reset = true;
}
if (module & NETSTATS_LAYER2) {
_netif_stats(iface, NETSTATS_LAYER2, reset);
}
if (module & NETSTATS_IPV6) {
_netif_stats(iface, NETSTATS_IPV6, reset);
}
return 1;
}
#endif
else if (strcmp(argv[2], "help") == 0) {
_usage(argv[0]);
return 0;
}
else {
return _netif_flag(argv[0], iface, argv[2]);
}
}
_usage(argv[0]);
return 1;
}
SHELL_COMMAND(ifconfig, "Configure network interfaces", _gnrc_netif_config);