From patchwork Fri Apr 27 21:24:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Aring X-Patchwork-Id: 10369867 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6D954601D3 for ; Fri, 27 Apr 2018 21:24:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5CE23287E2 for ; Fri, 27 Apr 2018 21:24:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 514A2294F4; Fri, 27 Apr 2018 21:24:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 31CB1294F2 for ; Fri, 27 Apr 2018 21:24:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759114AbeD0VYp (ORCPT ); Fri, 27 Apr 2018 17:24:45 -0400 Received: from mail-io0-f195.google.com ([209.85.223.195]:36583 "EHLO mail-io0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1759079AbeD0VYo (ORCPT ); Fri, 27 Apr 2018 17:24:44 -0400 Received: by mail-io0-f195.google.com with SMTP id d73-v6so4049999iog.3 for ; Fri, 27 Apr 2018 14:24:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mojatatu-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=CT9qV43SU15jNPBLc4Yeg1aHe3q/eHpC3/t9XD5nvLM=; b=ezkqJs8bbW3yohEbZm5g3Q36TrEfl0Axddp5+3OCYl4c+Y1ferDmN6STCEMjJrFU/a SKaFs6TidISNip+vtRMJAYx+A69dh+g265Vkw7S3jLR4QSXOkTrz/2FcgoR+J6zgwqCQ Ym75MgBeDbB4hrj6803IS5EQCjiwQkhGJzdRylJXLaElWP6vL5PAgKduQ4CI0KCd3iD8 YFna9k4JfMrPxahgQhOfnF62OG/PQpPBdhWEiWVYVOQT/mIMI0GCB5bMvRYTHP6BZnID UyDt76T5jlxqnxKG7sFTsQgogDCO7cX7jb/8QGGEHNb0+NglaRHUYIQudgasdgvO/GQG aUAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CT9qV43SU15jNPBLc4Yeg1aHe3q/eHpC3/t9XD5nvLM=; b=ePqRj9TEGOHSFcf79yVteuJ9JGkOEAdTLb6/FlQeK+8Tq+61s+v/IH54Usy2LiH29l S7PJJkjofCE0q0wrEJwekKcqSKdVYEDTznUzT9Ov5rNXoSXBcAB29F8qyKL7G/IBUyZ9 OBiSfMTfb7/5SpDbyLwUi61HJ8qFyXJ25X69DSL3Rl24g4QOqbTvxe4n1SttIT47ZgMg 12wja7YNXuVJtuugKY6W+MGI4QxxqJv13IOwx/AMC/D6nfUm/VIJQh5JMPkN8e8fLMKj WDJyNU2lu7nweXG0nmMx3j4AZsoCNEt4+ZB/XO93J5iZKSet3leCmlxPRgs0k3vx+j7w B22Q== X-Gm-Message-State: ALQs6tDuUerwj03cEepDuupDHZK1OKG9E46kFrGum1oSjByMAcJiID7z aaQAz1StYp420Y8Aryi94b7weA== X-Google-Smtp-Source: AB8JxZq9KzZRJEP+7j/3VsO/hh+DzG/yrUY6S6wttbY+SBB0vCmBtlEcso12mXGl/jfVo0fi3IKq/w== X-Received: by 2002:a6b:9c50:: with SMTP id f77-v6mr4011047ioe.286.1524864283892; Fri, 27 Apr 2018 14:24:43 -0700 (PDT) Received: from x220t.lan ([64.26.149.125]) by smtp.gmail.com with ESMTPSA id r23-v6sm1050482ioe.9.2018.04.27.14.24.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 27 Apr 2018 14:24:43 -0700 (PDT) From: Alexander Aring To: stefan@osg.samsung.com Cc: linux-wpan@vger.kernel.org, kernel@mojatatu.com, Alexander Aring Subject: [RFC PATCH wpan-tools 2/2] wpan-hwsim: initial commit Date: Fri, 27 Apr 2018 17:24:18 -0400 Message-Id: <20180427212418.29729-3-aring@mojatatu.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180427212418.29729-1-aring@mojatatu.com> References: <20180427212418.29729-1-aring@mojatatu.com> Sender: linux-wpan-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wpan@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds initial support for wpan-hwsim utility to control the mac802154_hwsim driver over netlink. Signed-off-by: Alexander Aring --- Makefile.am | 1 + configure.ac | 1 + wpan-hwsim/Makefile.am | 8 + wpan-hwsim/mac802154_hwsim.h | 73 +++++++ wpan-hwsim/wpan-hwsim.c | 509 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 592 insertions(+) create mode 100644 wpan-hwsim/Makefile.am create mode 100644 wpan-hwsim/mac802154_hwsim.h create mode 100644 wpan-hwsim/wpan-hwsim.c diff --git a/Makefile.am b/Makefile.am index 37f18b6..3f15825 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,4 +21,5 @@ AM_LDFLAGS = \ SUBDIRS = \ src \ wpan-ping \ + wpan-hwsim \ examples diff --git a/configure.ac b/configure.ac index 5dd59dc..a983532 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,7 @@ AC_CONFIG_FILES([ Makefile src/Makefile wpan-ping/Makefile + wpan-hwsim/Makefile examples/Makefile ]) diff --git a/wpan-hwsim/Makefile.am b/wpan-hwsim/Makefile.am new file mode 100644 index 0000000..f688cd9 --- /dev/null +++ b/wpan-hwsim/Makefile.am @@ -0,0 +1,8 @@ +bin_PROGRAMS = wpan-hwsim + +wpan_hwsim_SOURCES = wpan-hwsim.c + +wpan_hwsim_CFLAGS = $(AM_CFLAGS) $(LIBNL3_CFLAGS) +wpan_hwsim_LDADD = $(LIBNL3_LIBS) + +EXTRA_DIST = README.wpan-hwsim diff --git a/wpan-hwsim/mac802154_hwsim.h b/wpan-hwsim/mac802154_hwsim.h new file mode 100644 index 0000000..6009214 --- /dev/null +++ b/wpan-hwsim/mac802154_hwsim.h @@ -0,0 +1,73 @@ +#ifndef __MAC802154_HWSIM_H +#define __MAC802154_HWSIM_H + +/* mac802154 hwsim netlink commands + * + * @MAC802154_HWSIM_CMD_UNSPEC: unspecified command to catch error + * @MAC802154_HWSIM_CMD_GET_RADIO: fetch information about existing radios + * @MAC802154_HWSIM_CMD_SEL_RADIO: change radio parameters during runtime + * @MAC802154_HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters + * returns the radio ID (>= 0) or negative on errors, if successful + * then multicast the result + * @MAC802154_HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted + * @MAC802154_HWSIM_CMD_GET_EDGE: fetch information about existing edges + * @MAC802154_HWSIM_CMD_SET_EDGE: change edge parameters during runtime + * @MAC802154_HWSIM_CMD_DEL_EDGE: delete edges between radios + * @MAC802154_HWSIM_CMD_NEW_EDGE: create a new edge between two radios + * @__MAC802154_HWSIM_CMD_MAX: enum limit + */ +enum { + MAC802154_HWSIM_CMD_UNSPEC, + + MAC802154_HWSIM_CMD_GET_RADIO, + MAC802154_HWSIM_CMD_SET_RADIO, + MAC802154_HWSIM_CMD_NEW_RADIO, + MAC802154_HWSIM_CMD_DEL_RADIO, + + MAC802154_HWSIM_CMD_GET_EDGE, + MAC802154_HWSIM_CMD_SET_EDGE, + MAC802154_HWSIM_CMD_DEL_EDGE, + MAC802154_HWSIM_CMD_NEW_EDGE, + + __MAC802154_HWSIM_CMD_MAX, +}; + +#define MAC802154_HWSIM_CMD_MAX (__MAC802154_HWSIM_MAX - 1) + +/* mac802154 hwsim netlink attributes + * + * @MAC802154_HWSIM_ATTR_UNSPEC: unspecified attribute to catch error + * @MAC802154_HWSIM_ATTR_RADIO_ID: u32 attribute to identify the radio + * @MAC802154_HWSIM_ATTR_EDGE: nested attribute of edges + * @MAC802154_HWSIM_ATTR_EDGES: list if nested attributes which contains the + * edge information according the radio id + * @__MAC802154_HWSIM_ATTR_MAX: enum limit + */ +enum { + MAC802154_HWSIM_ATTR_UNSPEC, + MAC802154_HWSIM_ATTR_RADIO_ID, + MAC802154_HWSIM_ATTR_RADIO_EDGE, + MAC802154_HWSIM_ATTR_RADIO_EDGES, + __MAC802154_HWSIM_ATTR_MAX, +}; + +#define MAC802154_HWSIM_ATTR_MAX (__MAC802154_HWSIM_ATTR_MAX - 1) + +/* mac802154 hwsim edge netlink attributes + * + * @MAC802154_HWSIM_EDGE_ATTR_UNSPEC: unspecified attribute to catch error + * @MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID: radio id where the edge points to + * @MAC802154_HWSIM_EDGE_ATTR_LQI: LQI value which the endpoint radio will + * receive for this edge + * @__MAC802154_HWSIM_ATTR_MAX: enum limit + */ +enum { + MAC802154_HWSIM_EDGE_ATTR_UNSPEC, + MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID, + MAC802154_HWSIM_EDGE_ATTR_LQI, + __MAC802154_HWSIM_EDGE_ATTR_MAX, +}; + +#define MAC802154_HWSIM_EDGE_ATTR_MAX (__MAC802154_HWSIM_EDGE_ATTR_MAX - 1) + +#endif /* __MAC802154_HWSIM_H */ diff --git a/wpan-hwsim/wpan-hwsim.c b/wpan-hwsim/wpan-hwsim.c new file mode 100644 index 0000000..2d74e99 --- /dev/null +++ b/wpan-hwsim/wpan-hwsim.c @@ -0,0 +1,509 @@ +/* + * Linux IEEE 802.15.4 hwsim tool + * + * Copyright (C) 2018 Alexander Aring + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "mac802154_hwsim.h" + +static struct nl_sock *nl_sock; +static int nlhwsim_id; + +static int nlhwsim_init(void) +{ + int err; + + nl_sock = nl_socket_alloc(); + if (!nl_sock) { + fprintf(stderr, "Failed to allocate netlink socket.\n"); + return -ENOMEM; + } + + nl_socket_set_buffer_size(nl_sock, 8192, 8192); + + if (genl_connect(nl_sock)) { + fprintf(stderr, "Failed to connect to generic netlink.\n"); + err = -ENOLINK; + goto out_handle_destroy; + } + + nlhwsim_id = genl_ctrl_resolve(nl_sock, "MAC802154_HWSIM"); + if (nlhwsim_id < 0) { + fprintf(stderr, "MAC802154_HWSIM not found.\n"); + err = -ENOENT; + nl_close(nl_sock); + goto out_handle_destroy; + } + + return 0; + +out_handle_destroy: + nl_socket_free(nl_sock); + return err; +} + +static void nlhwsim_cleanup(void) +{ + nl_close(nl_sock); + nl_socket_free(nl_sock); +} + +static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, + void *arg) +{ + int *ret = arg; + *ret = err->error; + return NL_STOP; +} + +static int hwsim_create(void) +{ + struct nl_msg *msg; + struct nl_cb *cb; + int idx = 0, ret; + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + return -ENOMEM; + + msg = nlmsg_alloc(); + if (!cb) { + nl_cb_put(cb); + return -ENOMEM; + } + + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, 0, + MAC802154_HWSIM_CMD_NEW_RADIO, 0); + ret = nl_send_auto(nl_sock, msg); + if (ret < 0) { + nl_cb_put(cb); + return ret; + } + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &idx); + nl_recvmsgs(nl_sock, cb); + printf("wpan_hwsim radio%d registered.\n", idx); + + nl_cb_put(cb); + + return 0; +} + +static int nl_msg_dot_cb(struct nl_msg* msg, void* arg) +{ + static struct nla_policy edge_policy[MAC802154_HWSIM_EDGE_ATTR_MAX + 1] = { + [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] = { .type = NLA_U32 }, + [MAC802154_HWSIM_EDGE_ATTR_LQI] = { .type = NLA_U8 }, + }; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(nlh); + struct nlattr *attrs[MAC802154_HWSIM_ATTR_MAX + 1]; + struct nlattr *edge[MAC802154_HWSIM_EDGE_ATTR_MAX + 1]; + unsigned int *ignore_idx = arg; + struct nlattr *nl_edge; + uint32_t idx, idx2; + uint8_t lqi; + int rem_edge; + int rc; + + nla_parse(attrs, MAC802154_HWSIM_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!attrs[MAC802154_HWSIM_ATTR_RADIO_ID]) + return NL_SKIP; + + idx = nla_get_u32(attrs[MAC802154_HWSIM_ATTR_RADIO_ID]); + if (idx == *ignore_idx) + return NL_SKIP; + + if (!attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES]) + return NL_SKIP; + + nla_for_each_nested(nl_edge, attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES], + rem_edge) { + rc = nla_parse_nested(edge, MAC802154_HWSIM_EDGE_ATTR_MAX, + nl_edge, edge_policy); + if (rc) + return NL_SKIP; + + idx2 = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]); + if (idx2 == *ignore_idx) + continue; + + lqi = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_LQI]); + printf("\t%" PRIu32 " -> %" PRIu32 "[label=%" PRIu8 "];\n", + idx, idx2, lqi); + } + + return NL_SKIP; +} + +static int nl_msg_cb(struct nl_msg* msg, void* arg) +{ + static struct nla_policy edge_policy[MAC802154_HWSIM_EDGE_ATTR_MAX + 1] = { + [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] = { .type = NLA_U32 }, + [MAC802154_HWSIM_EDGE_ATTR_LQI] = { .type = NLA_U8 }, + }; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = (struct genlmsghdr*) nlmsg_data(nlh); + struct nlattr *attrs[MAC802154_HWSIM_ATTR_MAX + 1]; + struct nlattr *edge[MAC802154_HWSIM_EDGE_ATTR_MAX + 1]; + unsigned int *ignore_idx = arg; + struct nlattr *nl_edge; + uint32_t idx; + uint8_t lqi; + int rem_edge; + int rc; + + nla_parse(attrs, MAC802154_HWSIM_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!attrs[MAC802154_HWSIM_ATTR_RADIO_ID]) + return NL_SKIP; + + idx = nla_get_u32(attrs[MAC802154_HWSIM_ATTR_RADIO_ID]); + + if (idx == *ignore_idx) + return NL_SKIP; + + printf("wpan_hwsim radio%" PRIu32 ":\n", idx); + + if (!attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES]) + return NL_SKIP; + + nla_for_each_nested(nl_edge, attrs[MAC802154_HWSIM_ATTR_RADIO_EDGES], + rem_edge) { + rc = nla_parse_nested(edge, MAC802154_HWSIM_EDGE_ATTR_MAX, + nl_edge, edge_policy); + if (rc) + return NL_SKIP; + + idx = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]); + + if (idx == *ignore_idx) + continue; + + printf("\tedge:\n"); + printf("\t\tradio%" PRIu32 "\n", idx); + lqi = nla_get_u32(edge[MAC802154_HWSIM_EDGE_ATTR_LQI]); + printf("\t\tlqi: 0x%02x\n", lqi); + } + + return NL_SKIP; +} + +static int hwsim_dump(bool dot, int unsigned ignore_idx) +{ + struct nl_msg *msg; + int rc; + + nl_socket_modify_cb(nl_sock, NL_CB_VALID, NL_CB_CUSTOM, + dot ? nl_msg_dot_cb : nl_msg_cb, &ignore_idx); + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, NLM_F_DUMP, + MAC802154_HWSIM_CMD_GET_RADIO, 0); + + if (dot) + printf("digraph {\n"); + + rc = nl_send_sync(nl_sock, msg); + if (rc < 0) + return rc; + + if (dot) + printf("}\n"); + + return rc; +} + +static int hwsim_del(uint32_t idx) +{ + struct nl_msg *msg; + struct nl_cb *cb; + int err = 0; + int rc; + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + return -ENOMEM; + + msg = nlmsg_alloc(); + if (!msg) { + nl_cb_put(cb); + return -ENOMEM; + } + + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, 0, + MAC802154_HWSIM_CMD_DEL_RADIO, 0); + nla_put_u32(msg, MAC802154_HWSIM_ATTR_RADIO_ID, idx); + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); + rc = nl_send_auto(nl_sock, msg); + nl_recvmsgs(nl_sock, cb); + if (err < 0) + fprintf(stderr, "Failed to remove radio: %s\n", strerror(abs(err))); + nl_cb_put(cb); + + return rc; +} + +static int hwsim_cmd_edge(int cmd, uint32_t idx, uint32_t idx2, uint8_t lqi) +{ + struct nlattr* edge; + struct nl_msg *msg; + struct nl_cb *cb; + int err = 0; + int rc; + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + return -ENOMEM; + + msg = nlmsg_alloc(); + if (!msg) { + nl_cb_put(cb); + return -ENOMEM; + } + + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, nlhwsim_id, 0, 0, + cmd, 0); + nla_put_u32(msg, MAC802154_HWSIM_ATTR_RADIO_ID, idx); + + edge = nla_nest_start(msg, MAC802154_HWSIM_ATTR_RADIO_EDGE); + if (!edge) { + nl_cb_put(cb); + return -ENOMEM; + } + + nla_put_u32(msg, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID, idx2); + if (cmd == MAC802154_HWSIM_CMD_SET_EDGE) + nla_put_u8(msg, MAC802154_HWSIM_EDGE_ATTR_LQI, lqi); + + nla_nest_end(msg, edge); + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err); + rc = nl_send_auto(nl_sock, msg); + nl_recvmsgs(nl_sock, cb); + if (err < 0) + fprintf(stderr, "Failed to add or remove edge: %s\n", strerror(abs(err))); + nl_cb_put(cb); + + return rc; +} + +static int hwsim_do_cmd(uint32_t cmd, unsigned int idx, unsigned int idx2, + uint8_t lqi, bool dot, unsigned int ignore_idx) +{ + int rc; + + rc = nlhwsim_init(); + if (rc) + return 1; + + switch (cmd) { + case MAC802154_HWSIM_CMD_GET_RADIO: + rc = hwsim_dump(dot, ignore_idx); + break; + case MAC802154_HWSIM_CMD_DEL_RADIO: + rc = hwsim_del(idx); + break; + case MAC802154_HWSIM_CMD_NEW_RADIO: + rc = hwsim_create(); + break; + case MAC802154_HWSIM_CMD_NEW_EDGE: + case MAC802154_HWSIM_CMD_DEL_EDGE: + case MAC802154_HWSIM_CMD_SET_EDGE: + rc = hwsim_cmd_edge(cmd, idx, idx2, lqi); + break; + default: + rc = -EINVAL; + break; + } + + nlhwsim_cleanup(); + + return rc; +} + +static void print_usage(void) +{ + printf("wpan_hwsim [OPTION...] [CMD...]\n"); + printf("\n"); + printf(" possible options:\n"); + printf(" -h, --help show this help\n"); + printf(" -v, --version show version\n"); + printf(" -d, --dot dump topology as dot format\n"); + printf(" -i, --ignore filter one node from dump (useful for virtual monitors)\n"); + printf("\n"); + printf(" possible commands:\n"); + printf(" add add new hwsim radio\n"); + printf(" del IDX del hwsim radio according idx\n"); + printf(" edge add IDX IDX add edge between radios\n"); + printf(" edge del IDX IDX delete edge between radios\n"); + printf(" edge lqi IDX IDX LQI set lqi value for a specific edge\n"); + printf("\n"); + printf(" To dump all node information just call this program without any command\n"); +} + +static void print_version(void) +{ + printf("0.1\n"); +} + +int main(int argc, const char *argv[]) +{ + unsigned long int idx, idx2, lqi, ignore_idx = ULONG_MAX; + bool dot = false; + int cmd; + int rc; + int c; + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"help", required_argument, 0, 'h' }, + {"version", required_argument, 0, 'v' }, + {"dot", required_argument, 0, 'd' }, + {"ignore", required_argument, 0, 'i' }, + {0, 0, 0, 0 } + }; + + c = getopt_long(argc, (char **)argv, "vhdi:", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'v': + print_version(); + return EXIT_SUCCESS; + case 'h': + print_usage(); + return EXIT_SUCCESS; + case 'd': + dot = true; + break; + case 'i': + ignore_idx = strtoul(optarg, NULL, 0); + if (ignore_idx == ULONG_MAX) { + fprintf(stderr, "Invalid radio index for ignore argument\n"); + return EXIT_FAILURE; + } + break; + default: + print_usage(); + return EXIT_FAILURE; + } + } + + if (optind + 1 > argc) { + rc = hwsim_do_cmd(MAC802154_HWSIM_CMD_GET_RADIO, 0, 0, 0, dot, + ignore_idx); + if (rc < 0) + return EXIT_FAILURE; + else + goto out; + } + + if (!strncmp(argv[optind], "add", 3)) { + rc = hwsim_do_cmd(MAC802154_HWSIM_CMD_NEW_RADIO, 0, 0, 0, 0, 0); + if (rc < 0) + return EXIT_FAILURE; + } else if (!strncmp(argv[optind], "del", 3)) { + if (optind + 2 > argc) { + fprintf(stderr, "Missing radio index for delete\n"); + return EXIT_FAILURE; + } else { + idx = strtoul(argv[optind + 1], NULL, 0); + if (idx == ULONG_MAX) { + fprintf(stderr, "Invalid radio index for delete\n"); + return EXIT_FAILURE; + } + + rc = hwsim_do_cmd(MAC802154_HWSIM_CMD_DEL_RADIO, idx, 0, 0, 0, 0); + if (rc < 0) + return EXIT_FAILURE; + } + } else if (!strncmp(argv[optind], "edge", 4)) { + if (optind + 4 > argc) { + fprintf(stderr, "Missing edge radio index information\n"); + return EXIT_FAILURE; + } else { + if (!strncmp(argv[optind + 1], "add", 3)) { + cmd = MAC802154_HWSIM_CMD_NEW_EDGE; + } else if (!strncmp(argv[optind + 1], "del", 3)) { + cmd = MAC802154_HWSIM_CMD_DEL_EDGE; + } else if (!strncmp(argv[optind + 1], "lqi", 3)) { + cmd = MAC802154_HWSIM_CMD_SET_EDGE; + } else { + fprintf(stderr, "Invalid edge command\n"); + return EXIT_FAILURE; + } + + if (cmd == MAC802154_HWSIM_CMD_SET_EDGE) { + if (optind + 5 > argc) { + fprintf(stderr, "LQI information missing\n"); + return EXIT_FAILURE; + } + + lqi = strtoul(argv[optind + 4], NULL, 0); + if (lqi == ULONG_MAX || lqi > 0xff || lqi < 0) { + fprintf(stderr, "Invalid lqi value\n"); + return EXIT_FAILURE; + } + } + + idx = strtoul(argv[optind + 2], NULL, 0); + if (idx == ULONG_MAX) { + fprintf(stderr, "Invalid first radio index for edge command\n"); + return EXIT_FAILURE; + } + + idx2 = strtoul(argv[optind + 3], NULL, 0); + if (idx2 == ULONG_MAX) { + fprintf(stderr, "Invalid second radio index for edge command\n"); + return EXIT_FAILURE; + } + + rc = hwsim_do_cmd(cmd, idx, idx2, lqi, 0, 0); + if (rc < 0) + return EXIT_FAILURE; + } + } else { + fprintf(stderr, "Unknown command\n"); + print_usage(); + return EXIT_FAILURE; + } + +out: + return EXIT_SUCCESS; +}