mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
910e0e28ed
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>
1949 lines
57 KiB
C
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);
|