/* * 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 * @author Hauke Petersen * @author Oliver Hahm */ #include #include #include #include #include #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/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 }, { "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) { puts(" Protocol or device doesn't provide statistics."); } 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 [up|down]\n", cmd_name); } static void _set_usage(char *cmd_name) { printf("usage: %s set \n", cmd_name); puts(" Sets an hardware specific specific value\n" " 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" #ifdef MODULE_GNRC_NETIF_CMD_LORA " * \"bw\" - alias for channel bandwidth\n" " * \"sf\" - alias for spreading factor\n" " * \"cr\" - alias for coding rate\n" " * \"appeui\" - sets Application EUI\n" " * \"appkey\" - sets Application key\n" " * \"appskey\" - sets Application session key\n" " * \"deveui\" - sets Device EUI\n" " * \"dr\" - sets datarate\n" " * \"rx2_dr\" - sets datarate of RX2 (lorawan)\n" " * \"nwkskey\" - sets Network Session Key\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 [-]{", 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 add [anycast|multicast|unicast] " "[/prefix_len]\n", cmd_name); } static void _del_usage(char *cmd_name) { printf("usage: %s del \n", cmd_name); } #ifdef MODULE_NETSTATS static void _stats_usage(char *cmd_name) { printf("usage: %s stats [l2|ipv6] [reset]\n", cmd_name); puts(" reset can be only used if the module is specified."); } #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; case NETOPT_LORAWAN_NWKSKEY: printf("NwkSKey"); break; case NETOPT_LORAWAN_APPEUI: printf("AppEUI"); break; 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; #ifdef MODULE_GNRC_NETIF_CMD_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_GNRC_NETIF_CMD_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" }; #ifdef MODULE_GNRC_NETIF_CMD_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 #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_GNRC_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 (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; } } _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_GNRC_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 ", gnrc_netif_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); } #ifdef MODULE_GNRC_NETIF_CMD_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_GNRC_NETIF_CMD_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 link; res = netif_get_opt(iface, NETOPT_LINK, 0, &link, sizeof(netopt_enable_t)); if (res >= 0) { printf(" Link: %s ", (link == NETOPT_ENABLE) ? "up" : "down" ); } 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 ", gnrc_netif_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) { netopt_enable_t enable = NETOPT_DISABLE; res = netif_get_opt(iface, NETOPT_CSMA, 0, &enable, sizeof(enable)); if ((res >= 0) && (enable == NETOPT_ENABLE)) { printf(" CSMA Retries: %u ", (unsigned)u8); } line_thresh++; } #ifdef MODULE_GNRC_NETIF_CMD_LORA 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); #ifdef MODULE_GNRC_IPV6 printf("Link type: %s", (netif_get_opt(iface, NETOPT_IS_WIRED, 0, &u16, sizeof(u16)) > 0) ? "wired" : "wireless"); _newline(0U, ++line_thresh); 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 puts("\n White-listed link layer addresses:"); #else puts("\n Black-listed link layer addresses:"); #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]; gnrc_netif_addr_to_str(filter[i].addr, filter[i].addr_len, hwaddr_str); printf(" %2i: %s\n", count++, hwaddr_str); } } if (count == 0) { puts(" --- none ---"); } } #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) { puts("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) { puts("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; } #ifdef MODULE_GNRC_NETIF_CMD_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 { puts("usage: ifconfig set bw [125|250|500]"); 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 { puts("usage: ifconfig set cr [4/5|4/6|4/7|4/8]"); 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_GNRC_NETIF_CMD_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; } puts("usage: ifconfig set fec [none|NRNSC|RSC]"); 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 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) { puts("error: unable to parse value.\n" "Must be a 16-bit unsigned integer (dec or hex)\n"); return 1; } } else { if ((res = strtoul(u16_str, NULL, 16)) == ULONG_MAX) { puts("error: unable to parse value.\n" "Must be a 16-bit unsigned integer (dec or hex)\n"); return 1; } hex = true; } if (res > 0xffff) { puts("error: unable to parse value.\n" "Must be a 16-bit unsigned integer (dec or hex)\n"); return 1; } if (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) { puts("error: unable to set option"); return 1; } printf("success: %sset option\n", (set) ? "" : "un"); return 0; } #ifdef MODULE_GNRC_NETIF_CMD_LORA 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: /* 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) { puts("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 = gnrc_netif_addr_from_str(addr_str, addr); if (addr_len == 0) { puts("error: unable to parse address.\n" "Must be of format [0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*\n" "(hex pairs delimited by colons)"); return 1; } if (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 { puts("usage: ifconfig set state [off|sleep|idle|rx|tx|reset|standby]"); 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) { puts("error: unable to parse key"); return 1; } key[i / 2] = (uint8_t)((i1 << 4) + i2); } if (netif_set_opt(iface, opt, 0, key, key_len) < 0) { puts("error: unable to set encryption key"); 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 = gnrc_netif_addr_from_str(val, addr); if ((addr_len == 0) || (addr_len > CONFIG_L2FILTER_ADDR_MAXLEN)) { puts("error: given address is invalid"); return 1; } if (add) { if (netif_set_opt(iface, NETOPT_L2FILTER, 0, addr, addr_len) < 0) { puts("unable to add link layer address to filter"); return 1; } puts("successfully added address to filter"); } else { if (netif_set_opt(iface, NETOPT_L2FILTER_RM, 0, addr, addr_len) < 0) { puts("unable to remove link layer address from filter"); return 1; } puts("successfully removed address to filter"); } return 0; } static void _l2filter_usage(const char *cmd) { printf("usage: %s l2filter {add|del} \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); } #ifdef MODULE_GNRC_NETIF_CMD_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); } else if (strcmp("appeui", key) == 0) { return _netif_set_lw_key(iface, NETOPT_LORAWAN_APPEUI, 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("appskey", key) == 0) { return _netif_set_addr(iface, NETOPT_LORAWAN_APPSKEY, value); } else if (strcmp("nwkskey", key) == 0) { return _netif_set_addr(iface, NETOPT_LORAWAN_NWKSKEY, 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_GNRC_NETIF_CMD_LORA */ #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 (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; } 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) { puts("error: unable to parse IPv6 address."); 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; puts("error: unable to add IPv6 address."); 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) { puts("error: unable to parse IPv6 address."); 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; puts("error: unable to delete IPv6 address."); return 1; #endif } /* shell commands */ #ifdef MODULE_GNRC_TXTSND static int _gnrc_netif_send(int argc, char **argv) { netif_t *iface; uint8_t addr[GNRC_NETIF_L2ADDR_MAXLEN]; size_t addr_len; gnrc_pktsnip_t *pkt, *hdr; gnrc_netif_hdr_t *nethdr; uint8_t flags = 0x00; if (argc < 4) { printf("usage: %s [|bcast] \n", argv[0]); return 1; } iface = netif_get_by_name(argv[1]); if (!iface) { puts("error: invalid interface given"); return 1; } /* parse address */ addr_len = gnrc_netif_addr_from_str(argv[2], addr); if (addr_len == 0) { if (strcmp(argv[2], "bcast") == 0) { flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST; } else { puts("error: invalid address given"); return 1; } } /* put packet together */ pkt = gnrc_pktbuf_add(NULL, argv[3], strlen(argv[3]), GNRC_NETTYPE_UNDEF); if (pkt == NULL) { puts("error: packet buffer full"); return 1; } hdr = gnrc_netif_hdr_build(NULL, 0, addr, addr_len); if (hdr == NULL) { puts("error: packet buffer full"); gnrc_pktbuf_release(pkt); return 1; } pkt = gnrc_pkt_prepend(pkt, hdr); nethdr = (gnrc_netif_hdr_t *)hdr->data; nethdr->flags = flags; /* and send it */ if (gnrc_netif_send(container_of(iface, gnrc_netif_t, netif), pkt) < 1) { puts("error: unable to send"); gnrc_pktbuf_release(pkt); return 1; } return 0; } SHELL_COMMAND(txtsnd, "Sends a custom string as is over the link layer", _gnrc_netif_send); #endif /* TODO: updated tests/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 { puts("error: invalid interface given"); 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);