1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/shell/commands/sc_net_if.c
2014-10-24 09:55:31 +02:00

669 lines
17 KiB
C

/*
* 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 v2.1. 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 "inet_pton.h"
#include "inet_ntop.h"
#include "net_help.h"
#include "net_if.h"
#include "transceiver.h"
#ifndef MODULE_SIXLOWPAN
#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];
#else
#include "ipv6.h"
#endif
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, void *addr_data,
char *type, char *addr_data_str,
char *addr_data_len);
void _net_if_ifconfig_list(int if_id);
int is_number(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_LEGACY
" * 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 (is_number(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 (is_number(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 (is_number(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 (is_number(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;
}
#ifdef MODULE_SIXLOWPAN
ipv6_addr_t ipv6_addr;
void *addr_data = &ipv6_addr;
#else
void *addr_data = (void *)&addrs[addr_registered][0];
#endif
addr_data_str = strtok(addr_str, "/");
addr_data_len = strtok(NULL, "/");
if (!_net_if_ifconfig_ipv6_addr_convert(&addr, addr_data, type,
addr_data_str, addr_data_len)) {
add_usage();
return;
}
#ifdef MODULE_SIXLOWPAN
if (addr.addr_protocol & NET_IF_L3P_IPV6_PREFIX) {
if (ndp_add_prefix_info(if_id, &ipv6_addr, addr.addr_len,
NDP_OPT_PI_VLIFETIME_INFINITE,
NDP_OPT_PI_PLIFETIME_INFINITE, 1,
ICMPV6_NDP_OPT_PI_FLAG_AUTONOM) != SIXLOWERROR_SUCCESS) {
add_usage();
return;
}
}
else if (addr.addr_protocol & NET_IF_L3P_IPV6_ADDR) {
uint8_t is_anycast = 0;
if (addr.addr_protocol & NET_IF_L3P_IPV6_ANYCAST) {
is_anycast = 1;
}
if (!ipv6_net_if_add_addr(if_id, &ipv6_addr, NDP_ADDR_STATE_PREFERRED,
0, 0, is_anycast)) {
add_usage();
return;
}
}
else {
add_usage();
return;
}
#else
if (net_if_add_address(if_id, &addr) < 0) {
add_usage();
return;
}
addr_registered++;
#endif
}
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)
{
#ifdef MODULE_SIXLOWPAN
return ipv6_addr_is_multicast((ipv6_addr_t *) addr);
#else
return *addr == 0xff;
#endif
}
static inline int _is_link_local(uint8_t *addr)
{
#ifdef MODULE_SIXLOWPAN
return ipv6_addr_is_link_local((ipv6_addr_t *) addr);
#else
return (addr[0] == 0xfe && addr[1] == 0x80) ||
(_is_multicast(addr) && (addr[1] & 0x0f) == 2);
#endif
}
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, void *addr_data,
char *type, char *addr_data_str,
char *addr_data_len)
{
if (addr_data_len && !is_number(addr_data_len)) {
return 0;
}
addr->addr_data = addr_data;
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");
}
#ifdef MODULE_SIXLOWPAN
if (addr_ptr->addr_protocol & NET_IF_L3P_IPV6) {
char addr_str[IPV6_MAX_ADDR_STR_LEN];
printf(" inet6 addr: ");
if (inet_ntop(AF_INET6, addr_ptr->addr_data, addr_str,
IPV6_MAX_ADDR_STR_LEN)) {
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("global");
}
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");
}
}
#endif
}
puts("");
}