2015-03-02 18:41:37 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 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 devices
|
|
|
|
*
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
2015-03-11 22:54:52 +01:00
|
|
|
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
2015-03-02 18:41:37 +01:00
|
|
|
*/
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
#include <stdbool.h>
|
2015-03-02 18:41:37 +01:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "thread.h"
|
|
|
|
#include "net/ng_netif.h"
|
|
|
|
#include "net/ng_netapi.h"
|
|
|
|
#include "net/ng_netconf.h"
|
2015-03-11 22:54:52 +01:00
|
|
|
#include "net/ng_pkt.h"
|
2015-03-02 18:41:37 +01:00
|
|
|
#include "net/ng_pktbuf.h"
|
|
|
|
#include "net/ng_netif/hdr.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief The maximal expected link layer address length in byte
|
|
|
|
*/
|
2015-03-11 22:54:52 +01:00
|
|
|
#define MAX_ADDR_LEN (8U)
|
2015-03-02 18:41:37 +01:00
|
|
|
|
|
|
|
/* utility functions */
|
2015-03-11 22:54:52 +01:00
|
|
|
static bool _is_number(char *str)
|
|
|
|
{
|
|
|
|
for (; *str; str++) {
|
|
|
|
if (*str < '0' || *str > '9') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool _is_iface(kernel_pid_t dev)
|
|
|
|
{
|
|
|
|
size_t numof;
|
|
|
|
kernel_pid_t *ifs = ng_netif_get(&numof);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < numof; i++) {
|
|
|
|
if (ifs[i] == dev) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _set_usage(char *cmd_name)
|
|
|
|
{
|
|
|
|
printf("usage: %s <if_id> set <key> <value>\n", cmd_name);
|
|
|
|
puts(" Sets an hardware specific 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"
|
|
|
|
" * \"channel\" - sets the frequency channel\n"
|
|
|
|
" * \"chan\" - alias for \"channel\""
|
|
|
|
" * \"nid\" - sets the network identifier (or the PAN ID)\n"
|
|
|
|
" * \"pan\" - alias for \"nid\"\n"
|
|
|
|
" * \"pan_id\" - alias for \"nid\"\n"
|
|
|
|
" * \"src_len\" - sets the source address length in byte\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t _parse_hwaddr(char *str, uint8_t *addr)
|
2015-03-02 18:41:37 +01:00
|
|
|
{
|
|
|
|
char *tok = strtok(str, ":");
|
2015-03-11 22:54:52 +01:00
|
|
|
size_t res = 0;
|
2015-03-02 18:41:37 +01:00
|
|
|
|
|
|
|
while (tok != NULL) {
|
|
|
|
if (res >= MAX_ADDR_LEN) {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
unsigned int tmp = strtoul(tok, NULL, 16);
|
|
|
|
|
2015-03-02 18:41:37 +01:00
|
|
|
if (tmp <= 0xff) {
|
|
|
|
addr[res++] = (uint8_t)tmp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 0;
|
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
2015-03-02 18:41:37 +01:00
|
|
|
tok = strtok(NULL, ":");
|
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
2015-03-02 18:41:37 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
static void _print_hwaddr(uint8_t *addr, uint8_t addr_len)
|
2015-03-02 18:41:37 +01:00
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < addr_len; i++) {
|
|
|
|
printf("%02x", addr[i]);
|
2015-03-11 22:54:52 +01:00
|
|
|
|
2015-03-02 18:41:37 +01:00
|
|
|
if (i != (addr_len - 1)) {
|
|
|
|
printf(":");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
static void _print_netconf(ng_netconf_opt_t opt)
|
2015-03-02 18:41:37 +01:00
|
|
|
{
|
2015-03-11 22:54:52 +01:00
|
|
|
switch (opt) {
|
|
|
|
case NETCONF_OPT_ADDRESS:
|
|
|
|
printf("(short) address");
|
|
|
|
break;
|
2015-03-02 18:41:37 +01:00
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
case NETCONF_OPT_ADDRESS_LONG:
|
|
|
|
printf("long address");
|
|
|
|
break;
|
2015-03-02 18:41:37 +01:00
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
case NETCONF_OPT_SRC_LEN:
|
|
|
|
printf("source address length");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NETCONF_OPT_CHANNEL:
|
|
|
|
printf("channel");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NETCONF_OPT_NID:
|
|
|
|
printf("network identifier");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* we don't serve these options here */
|
|
|
|
break;
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
void _netif_list(kernel_pid_t dev)
|
2015-03-02 18:41:37 +01:00
|
|
|
{
|
2015-03-11 22:54:52 +01:00
|
|
|
uint8_t hwaddr[MAX_ADDR_LEN];
|
|
|
|
uint16_t u16;
|
|
|
|
int res;
|
2015-03-02 18:41:37 +01:00
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
printf("Iface %2d ", dev);
|
2015-03-02 18:41:37 +01:00
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
res = ng_netapi_get(dev, NETCONF_OPT_ADDRESS, 0, hwaddr, sizeof(hwaddr));
|
|
|
|
|
|
|
|
if (res >= 0) {
|
|
|
|
printf(" HWaddr: ");
|
|
|
|
_print_hwaddr(hwaddr, (uint8_t)res);
|
|
|
|
printf(" ");
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
res = ng_netapi_get(dev, NETCONF_OPT_CHANNEL, 0, &u16, sizeof(u16));
|
|
|
|
|
|
|
|
if (res >= 0) {
|
|
|
|
printf(" Channel: %" PRIu16 " ", u16);
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
res = ng_netapi_get(dev, NETCONF_OPT_NID, 0, &u16, sizeof(u16));
|
|
|
|
|
|
|
|
if (res >= 0) {
|
2015-03-19 18:18:16 +01:00
|
|
|
printf(" NID: 0x%" PRIx16 " ", u16);
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
printf("\n ");
|
|
|
|
|
|
|
|
res = ng_netapi_get(dev, NETCONF_OPT_ADDRESS_LONG, 0, hwaddr, sizeof(hwaddr));
|
|
|
|
|
|
|
|
if (res >= 0) {
|
|
|
|
printf("Long HWaddr: ");
|
|
|
|
_print_hwaddr(hwaddr, (uint8_t)res);
|
|
|
|
printf("\n ");
|
|
|
|
}
|
|
|
|
|
|
|
|
res = ng_netapi_get(dev, NETCONF_OPT_SRC_LEN, 0, &u16, sizeof(u16));
|
|
|
|
|
|
|
|
if (res >= 0) {
|
2015-03-19 18:18:16 +01:00
|
|
|
printf("Source address length: %" PRIu16 "\n ", u16);
|
2015-03-11 22:54:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: list IPv6 info */
|
|
|
|
|
|
|
|
puts("");
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
static void _netif_set_u16(kernel_pid_t dev, ng_netconf_opt_t opt,
|
|
|
|
char *u16_str)
|
2015-03-02 18:41:37 +01:00
|
|
|
{
|
2015-03-11 22:54:52 +01:00
|
|
|
unsigned int res;
|
|
|
|
bool hex = false;
|
2015-03-02 18:41:37 +01:00
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
if (_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;
|
|
|
|
}
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
hex = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res > 0xffff) {
|
|
|
|
puts("error: unable to parse value.\n"
|
|
|
|
"Must be a 16-bit unsigned integer (dec or hex)\n");
|
2015-03-02 18:41:37 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
if (ng_netapi_set(dev, opt, 0, (uint16_t *)&res, sizeof(uint16_t)) < 0) {
|
|
|
|
printf("error: unable to set ");
|
|
|
|
_print_netconf(opt);
|
|
|
|
puts("");
|
2015-03-20 15:10:01 +01:00
|
|
|
return;
|
2015-03-11 22:54:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
printf("success: set ");
|
|
|
|
_print_netconf(opt);
|
|
|
|
printf(" on interface %" PRIkernel_pid " to ", dev);
|
|
|
|
|
|
|
|
if (hex) {
|
|
|
|
printf("0x%04x\n", res);
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
else {
|
2015-03-11 22:54:52 +01:00
|
|
|
printf("%u\n", res);
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
static void _netif_set_addr(kernel_pid_t dev, ng_netconf_opt_t opt,
|
|
|
|
char *addr_str)
|
2015-03-02 18:41:37 +01:00
|
|
|
{
|
2015-03-11 22:54:52 +01:00
|
|
|
uint8_t addr[MAX_ADDR_LEN];
|
|
|
|
size_t addr_len = _parse_hwaddr(addr_str, addr);
|
2015-03-02 18:41:37 +01:00
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
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)");
|
2015-03-20 15:10:01 +01:00
|
|
|
return;
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
if (ng_netapi_set(dev, opt, 0, addr, addr_len) < 0) {
|
|
|
|
printf("error: unable to set ");
|
|
|
|
_print_netconf(opt);
|
|
|
|
puts("");
|
2015-03-20 15:10:01 +01:00
|
|
|
return;
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
printf("success: set ");
|
|
|
|
_print_netconf(opt);
|
|
|
|
printf(" on interface %" PRIkernel_pid " to ", dev);
|
|
|
|
_print_hwaddr(addr, addr_len);
|
|
|
|
puts("");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _netif_set(char *cmd_name, kernel_pid_t dev, char *key, char *value)
|
|
|
|
{
|
|
|
|
if ((strcmp("addr", key) == 0) || (strcmp("addr_short", key) == 0)) {
|
|
|
|
_netif_set_addr(dev, NETCONF_OPT_ADDRESS, value);
|
|
|
|
}
|
|
|
|
else if (strcmp("addr_long", key) == 0) {
|
|
|
|
_netif_set_addr(dev, NETCONF_OPT_ADDRESS_LONG, value);
|
|
|
|
}
|
|
|
|
else if ((strcmp("channel", key) == 0) || (strcmp("chan", key) == 0)) {
|
|
|
|
_netif_set_u16(dev, NETCONF_OPT_CHANNEL, value);
|
|
|
|
}
|
|
|
|
else if ((strcmp("nid", key) == 0) || (strcmp("pan", key) == 0) ||
|
|
|
|
(strcmp("pan_id", key) == 0)) {
|
|
|
|
_netif_set_u16(dev, NETCONF_OPT_NID, value);
|
|
|
|
}
|
|
|
|
else if (strcmp("src_len", key) == 0) {
|
|
|
|
_netif_set_u16(dev, NETCONF_OPT_SRC_LEN, value);
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
else {
|
2015-03-11 22:54:52 +01:00
|
|
|
_set_usage(cmd_name);
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
/* shell commands */
|
|
|
|
void _netif_send(int argc, char **argv)
|
2015-03-02 18:41:37 +01:00
|
|
|
{
|
|
|
|
kernel_pid_t dev;
|
2015-03-11 22:54:52 +01:00
|
|
|
uint8_t addr[MAX_ADDR_LEN];
|
|
|
|
size_t addr_len;
|
|
|
|
ng_pktsnip_t *pkt;
|
|
|
|
ng_netif_hdr_t *nethdr;
|
2015-03-02 18:41:37 +01:00
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
if (argc < 4) {
|
|
|
|
printf("usage: %s <if> <addr> <data>\n", argv[0]);
|
2015-03-02 18:41:37 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
2015-03-02 18:41:37 +01:00
|
|
|
/* parse interface */
|
|
|
|
dev = (kernel_pid_t)atoi(argv[1]);
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
if (!_is_iface(dev)) {
|
2015-03-02 18:41:37 +01:00
|
|
|
puts("error: invalid interface given");
|
|
|
|
return;
|
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
|
|
|
|
/* parse address */
|
|
|
|
addr_len = _parse_hwaddr(argv[2], addr);
|
|
|
|
|
|
|
|
if (addr_len == 0) {
|
|
|
|
puts("error: invalid address given");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* put packet together */
|
|
|
|
pkt = ng_pktbuf_add(NULL, argv[3], strlen(argv[3]), NG_NETTYPE_UNDEF);
|
|
|
|
pkt = ng_pktbuf_add(pkt, NULL, sizeof(ng_netif_hdr_t) + addr_len,
|
|
|
|
NG_NETTYPE_UNDEF);
|
|
|
|
nethdr = (ng_netif_hdr_t *)pkt->data;
|
|
|
|
ng_netif_hdr_init(nethdr, 0, addr_len);
|
|
|
|
ng_netif_hdr_set_dst_addr(nethdr, addr, addr_len);
|
|
|
|
/* and send it */
|
|
|
|
ng_netapi_send(dev, pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _netif_config(int argc, char **argv)
|
|
|
|
{
|
|
|
|
if (argc < 2) {
|
|
|
|
size_t numof;
|
|
|
|
kernel_pid_t *ifs = ng_netif_get(&numof);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < numof; i++) {
|
|
|
|
_netif_list(ifs[i]);
|
|
|
|
return;
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
}
|
2015-03-11 22:54:52 +01:00
|
|
|
else if (_is_number(argv[1])) {
|
|
|
|
kernel_pid_t dev = (kernel_pid_t)atoi(argv[1]);
|
|
|
|
|
|
|
|
if (_is_iface(dev)) {
|
|
|
|
if (argc < 3) {
|
|
|
|
_netif_list(dev);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (strcmp(argv[2], "set") == 0) {
|
|
|
|
if (argc < 5) {
|
|
|
|
_set_usage(argv[0]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_netif_set(argv[0], dev, argv[3], argv[4]);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO implement add for IP addresses */
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
else {
|
2015-03-11 22:54:52 +01:00
|
|
|
puts("error: invalid interface given");
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 22:54:52 +01:00
|
|
|
printf("usage: %s [<if_id> set <key> <value>]]\n", argv[0]);
|
2015-03-02 18:41:37 +01:00
|
|
|
}
|