From patchwork Sat Jul 14 16:36:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Aring X-Patchwork-Id: 10524769 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 0B55C602B3 for ; Sat, 14 Jul 2018 16:36:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ED10E2899C for ; Sat, 14 Jul 2018 16:36:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E0B6728B62; Sat, 14 Jul 2018 16:36:11 +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 79E1C2899C for ; Sat, 14 Jul 2018 16:36:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726715AbeGNQzq (ORCPT ); Sat, 14 Jul 2018 12:55:46 -0400 Received: from mail-io0-f182.google.com ([209.85.223.182]:43546 "EHLO mail-io0-f182.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726618AbeGNQzq (ORCPT ); Sat, 14 Jul 2018 12:55:46 -0400 Received: by mail-io0-f182.google.com with SMTP id y10-v6so19116566ioa.10 for ; Sat, 14 Jul 2018 09:36:08 -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; bh=BrHz+w5wI7tsUsbbrD7mag2JBuXYPpzsIIg6D6d0PYA=; b=d790uC9r4ZP1VCDccX1gAvIWzsPOMSkO3+8tl9P3bVbFqBGGl2JgzmOTkun1fvZjO8 XKoincM2QodUpqDt1LIISICUH9UmTvMKedDSXvwnSrIDBvH054lx0XqVJYoo1tgUfFSx tiT3t8aWJD2Cg1P0inbBtDld1FEZO3RsYJQ/99Aqbr+ZMBfYg28O1hcBi/fOC8cau0o+ MxfALOgzQgZCsdrcpWtXnSkppByHPTiuxAsUjcVR3MtFIdL7eFGRBWHU3cB+Pu1O0Y/F BwtZLH/gXRq0qmN2caGtZ0lUm8BajQ+jFVmQ/XVY+ReGlUOSoO8Yx0wKmBqxaqPVwx5A DcZw== 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; bh=BrHz+w5wI7tsUsbbrD7mag2JBuXYPpzsIIg6D6d0PYA=; b=pZV3t8qGR/M47QFPj6m/oQX3ES3Xvlu+FcM4VMZpKay8pZkJ83YpyqcBnajwFJNzqQ KXWcuLWy4Ce3BAhL7uEpwXlPJLK1KACDwMAwemHHRi7DtGwR36TixUhQ1B1TS90Ig8sA woIqltQxHlzI0wPxkkxvxR6x9rZVL7lDk+0fYwtFktmtpt2rqRae83Mj6/oXnFLXYg3o TDhN5bs++8O02k/ZCxlBaaKENQ3rfKtW9tUnZ7Lpq1kp5EjNnQm/H29eEHakLyCDamcf Kyh2N39k+3AeM2swV/CN32czGFQhDPl5Ui1V3AdhvQLQSO0+beb59lPM5W6bZ6jVN1NW qxrg== X-Gm-Message-State: APt69E2WzbBJwZLiLt8ZbVGif5X5ZxZhPC17UJiqg3twndYVbjEHu2Sn LlM4uEus1NluKjBQ6wwZm8wzzg== X-Google-Smtp-Source: AAOMgpf1sZkDZmZkncRBbowudc16FnjXml5Q1psMiNuyFE3mEpPZx38tUnMRJJ70dkd2+2R98p8Skw== X-Received: by 2002:a6b:b751:: with SMTP id h78-v6mr36734267iof.164.1531586168252; Sat, 14 Jul 2018 09:36:08 -0700 (PDT) Received: from localhost.localdomain (ecp01.openface.ca. [207.115.96.130]) by smtp.gmail.com with ESMTPSA id e21-v6sm11871928iob.20.2018.07.14.09.36.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 14 Jul 2018 09:36:07 -0700 (PDT) From: Alexander Aring To: stefan@osg.samsung.com Cc: linux-wpan@vger.kernel.org, Alexander Aring Subject: [PATCHv2 wpan-tools] wpan-hwsim: hardware simulator configuration utility Date: Sat, 14 Jul 2018 12:36:01 -0400 Message-Id: <20180714163601.18074-1-aring@mojatatu.com> X-Mailer: git-send-email 2.11.0 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 | 510 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 593 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..6c6e30e --- /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_SET_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..f4ecf10 --- /dev/null +++ b/wpan-hwsim/wpan-hwsim.c @@ -0,0 +1,510 @@ +/* + * 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" +#include "config.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 (!msg) { + 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 = 0xff; + 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(PACKAGE_VERSION "\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) { + 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; +}