diff --git a/Makefile.dep b/Makefile.dep index 9d86d5abad67f84048a1dc88ca49d02804cb54f6..afa5b34ae1246a180d4c4e601652ac1cbb60efaf 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -108,3 +108,9 @@ ifneq (,$(filter net_if,$(USEMODULE))) USEMODULE += transceiver endif endif + +ifneq (,$(filter shell_commands,$(USEMODULE))) + ifneq (,$(filter net_if,$(USEMODULE))) + USEMODULE += net_help + endif +endif diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile index fbb5c12005f89d71c078387c2744ad5637d41025..f4d7dc8f69a57ddb582f4fd92c63b41fe75e206d 100644 --- a/sys/shell/commands/Makefile +++ b/sys/shell/commands/Makefile @@ -11,6 +11,10 @@ ifneq (,$(filter cc110x,$(USEMODULE))) SRC += sc_cc1100.c endif endif +ifneq (,$(filter net_if,$(USEMODULE))) + INCLUDES += -I$(RIOTBASE)/sys/net/include + SRC += sc_net_if.c +endif ifneq (,$(filter mci,$(USEMODULE))) SRC += sc_disk.c endif diff --git a/sys/shell/commands/sc_net_if.c b/sys/shell/commands/sc_net_if.c new file mode 100644 index 0000000000000000000000000000000000000000..790173abe24b4988da40a9d321a41e659adc63f6 --- /dev/null +++ b/sys/shell/commands/sc_net_if.c @@ -0,0 +1,613 @@ +/* + * Shell commands for network interfaces + * + * Copyright (C) 2013 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup shell_commands + * @{ + * @file sc_net_if.c + * @brief provides shell commands to configure network interfaces + * @author Martin Lenders <mlenders@inf.fu-berlin.de> + * @} + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "destiny/socket.h" /* for AF_INET6 */ +#include "inet_pton.h" +#include "inet_ntop.h" +#include "net_help.h" +#include "net_if.h" +#include "transceiver.h" + +#define ADDR_REGISTERED_MAX (6) +#define ADDRS_LEN_MAX (16) + +static uint8_t addr_registered = 0; +static uint8_t addrs[ADDR_REGISTERED_MAX][ADDRS_LEN_MAX]; + +void _net_if_ifconfig_add(int if_id, int argc, char **argv); +void _net_if_ifconfig_add_ipv6(int if_id, int argc, char **argv); +void _net_if_ifconfig_set(int if_id, char *key, char *value); +void _net_if_ifconfig_set_srcaddrmode(int if_id, char *mode); +void _net_if_ifconfig_set_eui64(int if_id, char *addr); +void _net_if_ifconfig_set_hwaddr(int if_id, char *addr); +void _net_if_ifconfig_set_pan_id(int if_id, char *pan_id); +void _net_if_ifconfig_set_channel(int if_id, char *channel); +void _net_if_ifconfig_create(char *transceivers_str); +int _net_if_ifconfig_ipv6_addr_convert(net_if_addr_t *addr, char *type, + char *addr_data_str, char *addr_data_len); +void _net_if_ifconfig_list(int if_id); + +int isnumber(char *str) +{ + for (; *str; str++) { + if (!isdigit((int)*str)) { + return 0; + } + } + + return 1; +} + +static inline void _eui64_to_str(char *eui64_str, net_if_eui64_t *eui64) +{ + sprintf(eui64_str, "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", + eui64->uint8[0], eui64->uint8[1], eui64->uint8[2], eui64->uint8[3], + eui64->uint8[4], eui64->uint8[5], eui64->uint8[6], eui64->uint8[7]); +} + +char *addr_data_to_str(char *addr_str, const uint8_t *addr, uint8_t addr_len) +{ + int i; + + for (i = 0; i < addr_len / 8; i++) { + sprintf(addr_str, "%02x", addr[i]); + } + + uint8_t r = addr_len % 8; + + if (r) { + uint8_t mask = 0x00; + + while (r) { + mask |= 0x1 << (8 - (r--)); + } + + sprintf(addr_str, "%02x", addr[addr_len / 8] & mask); + } + + return addr_str; +} + +void add_usage(void) +{ + puts("Usage: ifconfig <if_id> add ipv6 [multicast|anycast] <addr>"); +} + +void set_usage(void) +{ + printf("Usage: ifconfig <if_id> set <key> <value>\n" + " Sets an transceiver specific value\n" + " <key> may be one of the following\n" + " * \"srcaddrmode\" - sets the source address mode for IEEE\n" + " 802.15.4 transeivers (valid values: \"short\" or \"long\"),\n" + " * \"sam\" - alias for \"srcaddrmode\"\n" + " * \"eui64\" - sets the EUI-64 if supported by transceivers,\n" + " * \"hwaddr\" - sets the 16-bit address (or just the address\n" + " for e.g cc1100) of the transceivers\n" + " * \"pan_id\" - sets the PAN ID of the transceiver\n" + " * \"pan\" - alias for \"pan_id\"\n" + " * \"channel\" - sets the frequency channel of the transceiver\n" + " * \"chan\" - alias for \"channel\"\n"); +} + +void create_usage(void) +{ + puts("Usage: ifconfig create <transceiver_1>[,<transceiver_2>,...]\n" + " <transceiver_n> may be one of the following values:\n" +#ifdef MODULE_AT86RF231 + " * at86rv231\n" +#endif +#ifdef MODULE_CC1020 + " * cc1020\n" +#endif +#if MODULE_CC110X || MODULE_CC110X_NG + " * cc1100\n" +#endif +#ifdef MODULE_CC2420 + " * cc2420\n" +#endif +#ifdef MODULE_MC1322X + " * mc1322x\n" +#endif +#ifdef MODULE_NATIVENET + " * native\n" +#endif + ); +} + +void _net_if_ifconfig(int argc, char **argv) +{ + if (argc < 2) { + int if_id = -1; + + while ((if_id = net_if_iter_interfaces(if_id)) >= 0) { + _net_if_ifconfig_list(if_id); + } + + return; + } + else if (strcmp(argv[1], "create") == 0) { + _net_if_ifconfig_create(argv[2]); + return; + } + else if (isnumber(argv[1])) { + int if_id = atoi(argv[1]); + + if (argc < 3) { + _net_if_ifconfig_list(if_id); + return; + } + else if (strcmp(argv[2], "add") == 0) { + if (argc < 5) { + add_usage(); + return; + } + + _net_if_ifconfig_add(if_id, argc, argv); + return; + } + else if (strcmp(argv[2], "set") == 0) { + if (argc < 5) { + set_usage(); + return; + } + + _net_if_ifconfig_set(if_id, argv[3], argv[4]); + return; + } + } + + create_usage(); + printf("or: ifconfig [<if_id> [add <protocol> <addr>|set <key> <value>]]\n"); +} + +void _net_if_ifconfig_set_srcaddrmode(int if_id, char *mode) +{ + if (mode == NULL) { + set_usage(); + return; + } + else if (strcmp(mode, "short") == 0) { + net_if_set_src_address_mode(if_id, NET_IF_TRANS_ADDR_M_SHORT); + } + else if (strcmp(mode, "long") == 0) { + net_if_set_src_address_mode(if_id, NET_IF_TRANS_ADDR_M_LONG); + } + else { + set_usage(); + return; + } +} + +void _net_if_ifconfig_set_eui64(int if_id, char *eui64_str) +{ + net_if_eui64_t eui64; + + if (eui64_str == NULL) { + set_usage(); + return; + } + + net_if_hex_to_eui64(&eui64, eui64_str); + net_if_set_eui64(if_id, &eui64); +} + +void _net_if_ifconfig_set_hwaddr(int if_id, char *addr_str) +{ + int addr; + + if (addr_str == NULL) { + set_usage(); + return; + } + + if (isnumber(addr_str)) { + if ((addr = atoi(addr_str)) > 0xffff) { + set_usage(); + return; + } + } + else { + if ((addr = strtoul(addr_str, NULL, 16)) > 0xffff) { + set_usage(); + return; + } + } + + net_if_set_hardware_address(if_id, (uint16_t)addr); +} + +void _net_if_ifconfig_set_pan_id(int if_id, char *pan_str) +{ + int pan_id; + + if (pan_str == NULL) { + set_usage(); + return; + } + + if (isnumber(pan_str)) { + if ((pan_id = atoi(pan_str)) > 0xffff) { + set_usage(); + return; + } + } + else { + if ((pan_id = strtoul(pan_str, NULL, 16)) > 0xffff) { + set_usage(); + return; + } + } + + net_if_set_pan_id(if_id, (uint16_t) pan_id); +} + +void _net_if_ifconfig_set_channel(int if_id, char *chan_str) +{ + int channel; + + if (chan_str == NULL) { + set_usage(); + return; + } + + if (isnumber(chan_str)) { + if ((channel = atoi(chan_str)) > 0xffff) { + set_usage(); + return; + } + } + else { + if ((channel = strtoul(chan_str, NULL, 16)) > 0xffff) { + set_usage(); + return; + } + } + + net_if_set_channel(if_id, (uint16_t) channel); +} + +void _net_if_ifconfig_set(int if_id, char *key, char *value) +{ + if (strcmp(key, "sam") == 0 || strcmp(key, "srcaddrmode") == 0) { + _net_if_ifconfig_set_srcaddrmode(if_id, value); + } + else if (strcmp(key, "eui64") == 0) { + _net_if_ifconfig_set_eui64(if_id, value); + } + else if (strcmp(key, "hwaddr") == 0) { + _net_if_ifconfig_set_hwaddr(if_id, value); + } + else if (strcmp(key, "pan") == 0 || strcmp(key, "pan_id") == 0) { + _net_if_ifconfig_set_pan_id(if_id, value); + } + else if (strcmp(key, "chan") == 0 || strcmp(key, "channel") == 0) { + _net_if_ifconfig_set_channel(if_id, value); + } + else { + set_usage(); + return; + } +} + +void _net_if_ifconfig_add_ipv6(int if_id, int argc, char **argv) +{ + char *type; + char *addr_str; + char *addr_data_str; + char *addr_data_len; + net_if_addr_t addr; + + if (argc > 5) { + if (strcmp(argv[4], "multicast") == 0 || strcmp(argv[4], "anycast") == 0 || strcmp(argv[4], "unicast") == 0) { + type = argv[4]; + addr_str = argv[5]; + } + else { + add_usage(); + return; + } + } + else { + addr_str = argv[4]; + type = NULL; + } + + addr_data_str = strtok(addr_str, "/"); + addr_data_len = strtok(NULL, "/"); + + if (!_net_if_ifconfig_ipv6_addr_convert(&addr, type, addr_data_str, addr_data_len)) { + add_usage(); + return; + } + + if (net_if_add_address(if_id, &addr) < 0) { + add_usage(); + return; + } + + addr_registered++; +} + +void _net_if_ifconfig_add(int if_id, int argc, char **argv) +{ + if (strcmp(argv[3], "ipv6") == 0) { + _net_if_ifconfig_add_ipv6(if_id, argc, argv); + } + else { + add_usage(); + } +} + +void _net_if_ifconfig_create(char *transceivers_str) +{ + char *transceiver_str; + transceiver_type_t transceivers = TRANSCEIVER_NONE; + int iface; + + transceiver_str = strtok(transceivers_str, ","); + + while (transceiver_str) { + if (strcasecmp(transceiver_str, "at86rv231") == 0) { + transceivers |= TRANSCEIVER_AT86RF231; + } + else if (strcasecmp(transceiver_str, "cc1020") == 0) { + transceivers |= TRANSCEIVER_CC1020; + } + else if (strcasecmp(transceiver_str, "cc1100") == 0) { + transceivers |= TRANSCEIVER_CC1100; + } + else if (strcasecmp(transceiver_str, "cc2420") == 0) { + transceivers |= TRANSCEIVER_CC2420; + } + else if (strcasecmp(transceiver_str, "mc1322x") == 0) { + transceivers |= TRANSCEIVER_MC1322X; + } + else if (strcasecmp(transceiver_str, "native") == 0) { + transceivers |= TRANSCEIVER_NATIVE; + } + else { + create_usage(); + return; + } + + transceiver_str = strtok(NULL, ","); + } + + if (!transceivers) { + create_usage(); + return; + } + + iface = net_if_init_interface(NET_IF_L3P_RAW, transceivers); + + if (iface < 0) { + puts("Maximum number of allowed interfaces reached.\n"); + } + else { + printf("Initialized interface %d\n", iface); + } +} + +static inline int _is_multicast(uint8_t *addr) +{ + return *addr == 0xff; +} + +static inline int _is_link_local(uint8_t *addr) +{ + return (addr[0] == 0xfe && addr[1] == 0x80) || + (_is_multicast(addr) && (addr[1] & 0x0f) == 2); +} + +int _set_protocol_from_type(char *type, net_if_addr_t *addr) +{ + if (type != NULL) { + if ((strcmp(type, "multicast") == 0) && + _is_multicast((uint8_t *)addr->addr_data)) { + addr->addr_protocol |= NET_IF_L3P_IPV6_MULTICAST; + return 1; + } + else if ((strcmp(type, "anycast") == 0) && + addr->addr_protocol & NET_IF_L3P_IPV6_PREFIX) { + addr->addr_protocol |= NET_IF_L3P_IPV6_ANYCAST; + return 1; + } + + return 0; + } + else if (_is_multicast((uint8_t *)addr->addr_data)) { + addr->addr_protocol |= NET_IF_L3P_IPV6_MULTICAST; + return 1; + } + else { + addr->addr_protocol |= NET_IF_L3P_IPV6_UNICAST; + return 1; + } +} + +int _net_if_ifconfig_ipv6_addr_convert(net_if_addr_t *addr, char *type, + char *addr_data_str, char *addr_data_len) +{ + if (addr_data_len && !isnumber(addr_data_len)) { + return 0; + } + + addr->addr_data = (void *)&addrs[addr_registered][0]; + + if (!inet_pton(AF_INET6, addr_data_str, addr->addr_data)) { + return 0; + } + + else if (addr_data_len == NULL) { + addr->addr_len = 128; + addr->addr_protocol = 0; + + if (!_set_protocol_from_type(type, addr)) { + return 0; + } + } + else { + addr->addr_len = atoi(addr_data_len); + addr->addr_protocol = NET_IF_L3P_IPV6_PREFIX; + + if (addr->addr_len > 128 || !_set_protocol_from_type(type, addr)) { + return 0; + } + } + + return 1; +} + +void _net_if_ifconfig_list(int if_id) +{ + net_if_t *iface = net_if_get_interface(if_id); + transceiver_type_t transceivers; + uint16_t hw_address; + int32_t channel; + int32_t pan_id; + net_if_eui64_t eui64; + char eui64_str[24]; + net_if_addr_t *addr_ptr = NULL; + + if (!iface) { + return; + } + + transceivers = iface->transceivers; + hw_address = net_if_get_hardware_address(if_id); + channel = net_if_get_channel(if_id); + pan_id = net_if_get_pan_id(if_id); + net_if_get_eui64(&eui64, if_id, 0); + _eui64_to_str(eui64_str, &eui64); + + printf("Iface %3d HWaddr: 0x%04x", if_id, + hw_address); + + if (channel < 0) { + printf(" Channel: not set"); + } + else { + printf(" Channel: %d", (uint16_t) channel); + } + + if (pan_id < 0) { + printf(" PAN ID: not set"); + } + else { + printf(" PAN ID: 0x%04x", (uint16_t)pan_id); + } + + printf("\n"); + + printf(" EUI-64: %s\n", eui64_str); + + switch (net_if_get_src_address_mode(if_id)) { + case NET_IF_TRANS_ADDR_M_SHORT: + puts(" Source address mode: short"); + break; + + case NET_IF_TRANS_ADDR_M_LONG: + puts(" Source address mode: long"); + break; + + default: + puts(" Source address mode: unknown"); + break; + } + + puts(" Transceivers:"); + + if (transceivers & TRANSCEIVER_AT86RF231) { + puts(" * at86rf231"); + } + + if (transceivers & TRANSCEIVER_CC1020) { + puts(" * cc1020"); + } + + if (transceivers & TRANSCEIVER_CC1100) { + puts(" * cc1100"); + } + + if (transceivers & TRANSCEIVER_CC2420) { + puts(" * cc2420"); + } + + if (transceivers & TRANSCEIVER_MC1322X) { + puts(" * mc1322x"); + } + + if (transceivers & TRANSCEIVER_NATIVE) { + puts(" * native"); + } + + while (net_if_iter_addresses(if_id, &addr_ptr)) { + if (addr_ptr->addr_protocol == NET_IF_L3P_RAW) { + char addr_str[addr_ptr->addr_len / 4 + 3]; + + printf(" Raw L3 addr: 0x"); + printf("%s", addr_data_to_str(addr_str, addr_ptr->addr_data, + addr_ptr->addr_len)); + puts("\n"); + } + + if (addr_ptr->addr_protocol & NET_IF_L3P_IPV6) { + char addr_str[50]; + printf(" inet6 addr: "); + + if (inet_ntop(AF_INET6, addr_ptr->addr_data, addr_str, + addr_ptr->addr_len / 8 + 1)) { + printf("%s/%d", addr_str, addr_ptr->addr_len); + printf(" scope: "); + + if (addr_ptr->addr_len > 2 && _is_link_local((uint8_t *)addr_ptr->addr_data)) { + printf("local"); + } + else { + printf("local"); + } + + if (!(addr_ptr->addr_protocol & NET_IF_L3P_IPV6_UNICAST)) { + printf(" "); + + if (addr_ptr->addr_protocol & NET_IF_L3P_IPV6_MULTICAST) { + printf("[multicast]"); + } + else if (addr_ptr->addr_protocol & NET_IF_L3P_IPV6_ANYCAST) { + printf("[anycast]"); + } + } + + printf("\n"); + } + else { + printf("error in conversion\n"); + } + } + } + + puts(""); +} diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index da236fa7e858ba96dc43fa5debb0fd7b8dcd0ecb..f1740511daf73f756a1cc87432bcb07636a13695 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -100,6 +100,10 @@ extern void _transceiver_set_ignore_handler(int argc, char **argv); #endif #endif +#ifdef MODULE_NET_IF +extern void _net_if_ifconfig(int argc, char **argv); +#endif + #ifdef MODULE_MCI extern void _get_sectorsize(int argc, char **argv); extern void _get_blocksize(int argc, char **argv); @@ -137,7 +141,6 @@ const shell_command_t _shell_command_list[] = { {"cur", "Prints current and average power consumption.", _get_current_handler}, {"rstcur", "Resets coulomb counter.", _reset_current_handler}, #endif - #ifdef MODULE_TRANSCEIVER #ifdef _TC_ADDR {"addr", "Gets or sets the address for the transceiver", _transceiver_get_set_address_handler}, @@ -166,7 +169,9 @@ const shell_command_t _shell_command_list[] = { {"chan", "Gets or sets the channel for the CC1100 transceiver", _cc110x_get_set_channel_handler}, #endif #endif - +#ifdef MODULE_NET_IF + {"ifconfig", "Configures a network interface", _net_if_ifconfig}, +#endif #ifdef MODULE_MCI {DISK_READ_SECTOR_CMD, "Reads the specified sector of inserted memory card", _read_sector}, {DISK_READ_BYTES_CMD, "Reads the specified bytes from inserted memory card", _read_bytes}, @@ -178,6 +183,5 @@ const shell_command_t _shell_command_list[] = { { "mersenne_init", "initializes the PRNG", _mersenne_init }, { "mersenne_get", "returns 32 bit of pseudo randomness", _mersenne_get }, #endif - {NULL, NULL, NULL} };