From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.s-osg.org ([54.187.51.154]:40116 "EHLO lists.s-osg.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751436AbbI3Oqf (ORCPT ); Wed, 30 Sep 2015 10:46:35 -0400 Subject: Re: [PATCH wpan-tools 1/2] security: add nl802154 security support References: <1443425134-27910-1-git-send-email-alex.aring@gmail.com> From: Stefan Schmidt Message-ID: <560BF5C6.9090506@osg.samsung.com> Date: Wed, 30 Sep 2015 16:46:30 +0200 MIME-Version: 1.0 In-Reply-To: <1443425134-27910-1-git-send-email-alex.aring@gmail.com> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Sender: linux-wpan-owner@vger.kernel.org List-ID: To: Alexander Aring , linux-wpan@vger.kernel.org Cc: kernel@pengutronix.de, netdev@vger.kernel.org, phoebe.buckheister@itwm.fraunhofer.de Hello. A really huge patch. I will start on it. Not sure I can do a full review in one go though. On 28/09/15 09:25, Alexander Aring wrote: > This patch introduce support for the experimental seucirty support for Type. Security. > nl802154. We currently support add/del settings for manipulating > security table entries. The dump functionality is a "really" keep it is really a > short and stupid handling, the dump will printout the printout the right dump will printout the right calls to add the entry > add calls which was called to add the entry. This can be used for > storing the current security tables by some script. The interface > argument is replaced by $WPAN_DEV variable, so it's possible to move one > interface configuration to another one. > > Signed-off-by: Alexander Aring > --- > src/Makefile.am | 1 + > src/interface.c | 100 +++++ > src/nl802154.h | 191 ++++++++++ > src/security.c | 1118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 1410 insertions(+) > create mode 100644 src/security.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index 2d54576..b2177a2 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -9,6 +9,7 @@ iwpan_SOURCES = \ > interface.c \ > phy.c \ > mac.c \ > + security.c \ > nl_extras.h \ > nl802154.h > > diff --git a/src/interface.c b/src/interface.c > index 85d40a8..076e7c3 100644 > --- a/src/interface.c > +++ b/src/interface.c > @@ -10,6 +10,7 @@ > #include > #include > > +#define CONFIG_IEEE802154_NL802154_EXPERIMENTAL > #include "nl802154.h" > #include "nl_extras.h" > #include "iwpan.h" > @@ -226,6 +227,105 @@ static int print_iface_handler(struct nl_msg *msg, void *arg) > if (tb_msg[NL802154_ATTR_ACKREQ_DEFAULT]) > printf("%s\tackreq_default %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_ACKREQ_DEFAULT])); > > + if (tb_msg[NL802154_ATTR_SEC_ENABLED]) > + printf("%s\tsecurity %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_SEC_ENABLED])); > + if (tb_msg[NL802154_ATTR_SEC_OUT_LEVEL]) > + printf("%s\tout_level %d\n", indent, nla_get_u8(tb_msg[NL802154_ATTR_SEC_OUT_LEVEL])); > + if (tb_msg[NL802154_ATTR_SEC_OUT_KEY_ID]) { > + struct nlattr *tb_key_id[NL802154_KEY_ID_ATTR_MAX + 1]; > + static struct nla_policy key_id_policy[NL802154_KEY_ID_ATTR_MAX + 1] = { > + [NL802154_KEY_ID_ATTR_MODE] = { .type = NLA_U32 }, > + [NL802154_KEY_ID_ATTR_INDEX] = { .type = NLA_U8 }, > + [NL802154_KEY_ID_ATTR_IMPLICIT] = { .type = NLA_NESTED }, > + [NL802154_KEY_ID_ATTR_SOURCE_SHORT] = { .type = NLA_U32 }, > + [NL802154_KEY_ID_ATTR_SOURCE_EXTENDED] = { .type = NLA_U64 }, > + }; > + > + nla_parse_nested(tb_key_id, NL802154_KEY_ID_ATTR_MAX, > + tb_msg[NL802154_ATTR_SEC_OUT_KEY_ID], key_id_policy); > + printf("%s\tout_key_id\n", indent); > + > + if (tb_key_id[NL802154_KEY_ID_ATTR_MODE]) { > + enum nl802154_key_id_modes key_id_mode; > + > + key_id_mode = nla_get_u32(tb_key_id[NL802154_KEY_ID_ATTR_MODE]); > + switch (key_id_mode) { > + case NL802154_KEY_ID_MODE_IMPLICIT: > + printf("%s\t\tmode implicit\n", indent); > + if (tb_key_id[NL802154_KEY_ID_ATTR_IMPLICIT]) { > + struct nlattr *tb_dev_addr[NL802154_DEV_ADDR_ATTR_MAX + 1]; > + static struct nla_policy dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { > + [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, > + [NL802154_DEV_ADDR_ATTR_MODE] = { .type = NLA_U32 }, > + [NL802154_DEV_ADDR_ATTR_SHORT] = { .type = NLA_U16 }, > + [NL802154_DEV_ADDR_ATTR_EXTENDED] = { .type = NLA_U64 }, > + }; > + > + nla_parse_nested(tb_dev_addr, NL802154_DEV_ADDR_ATTR_MAX, > + tb_key_id[NL802154_KEY_ID_ATTR_IMPLICIT], > + dev_addr_policy); > + > + if (tb_dev_addr[NL802154_DEV_ADDR_ATTR_PAN_ID]) > + printf("%s\t\tpan_id 0x%04x\n", indent, > + le16toh(nla_get_u16(tb_dev_addr[NL802154_DEV_ADDR_ATTR_PAN_ID]))); > + > + if (tb_dev_addr[NL802154_DEV_ADDR_ATTR_MODE]) { > + enum nl802154_dev_addr_modes dev_addr_mode; > + dev_addr_mode = nla_get_u32(tb_dev_addr[NL802154_DEV_ADDR_ATTR_MODE]); > + printf("%s\t\taddr_mode %d\n", indent, dev_addr_mode); > + switch (dev_addr_mode) { > + case NL802154_DEV_ADDR_SHORT: > + if (tb_dev_addr[NL802154_DEV_ADDR_ATTR_SHORT]) > + printf("%s\t\tshort_addr 0x%04x\n", indent, > + le16toh(nla_get_u16(tb_dev_addr[NL802154_DEV_ADDR_ATTR_SHORT]))); > + break; > + case NL802154_DEV_ADDR_EXTENDED: > + if (tb_dev_addr[NL802154_DEV_ADDR_ATTR_EXTENDED]) > + printf("%s\t\textended_addr 0x%016" PRIx64 "\n", indent, > + le64toh(nla_get_u64(tb_dev_addr[NL802154_DEV_ADDR_ATTR_EXTENDED]))); > + break; > + default: > + printf("%s\t\tunkown address\n", indent); > + break; > + } > + } > + } > + break; > + case NL802154_KEY_ID_MODE_INDEX: > + printf("%s\t\tmode index\n", indent); > + if (tb_key_id[NL802154_KEY_ID_ATTR_INDEX]) > + printf("%s\t\tindex 0x%02x\n", indent, > + nla_get_u8(tb_key_id[NL802154_KEY_ID_ATTR_INDEX])); > + break; > + case NL802154_KEY_ID_MODE_INDEX_SHORT: > + printf("%s\t\tmode index_short\n", indent); > + if (tb_key_id[NL802154_KEY_ID_ATTR_INDEX]) > + printf("%s\t\tindex 0x%02x\n", indent, > + nla_get_u8(tb_key_id[NL802154_KEY_ID_ATTR_INDEX])); > + > + if (tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_SHORT]) > + printf("%s\t\tsource_short 0x%08lx\n", indent, > + le32toh(nla_get_u32(tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_SHORT]))); > + break; > + case NL802154_KEY_ID_MODE_INDEX_EXTENDED: > + printf("%s\t\tmode index_extended\n", indent); > + if (tb_key_id[NL802154_KEY_ID_ATTR_INDEX]) > + printf("%s\t\tindex 0x%02x\n", indent, > + nla_get_u8(tb_key_id[NL802154_KEY_ID_ATTR_INDEX])); > + > + if (tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED]) > + printf("%s\t\tsource_extended 0x%" PRIx64 "\n", indent, > + le64toh(nla_get_u64(tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED]))); > + break; > + default: > + printf("%s\t\tkey_mode unknown\n", indent); > + } > + } > + } > + > + if (tb_msg[NL802154_ATTR_SEC_FRAME_COUNTER]) > + printf("%s\tframe_counter 0x%08lx\n", indent, be32toh(nla_get_u32(tb_msg[NL802154_ATTR_SEC_FRAME_COUNTER]))); > + > return NL_SKIP; > } > > diff --git a/src/nl802154.h b/src/nl802154.h > index cf2713d..32cb3e5 100644 > --- a/src/nl802154.h > +++ b/src/nl802154.h > @@ -56,6 +56,22 @@ enum nl802154_commands { > > /* add new commands above here */ > > +#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL > + NL802154_CMD_SET_SEC_PARAMS, > + NL802154_CMD_GET_SEC_KEY, /* can dump */ > + NL802154_CMD_NEW_SEC_KEY, > + NL802154_CMD_DEL_SEC_KEY, > + NL802154_CMD_GET_SEC_DEV, /* can dump */ > + NL802154_CMD_NEW_SEC_DEV, > + NL802154_CMD_DEL_SEC_DEV, > + NL802154_CMD_GET_SEC_DEVKEY, /* can dump */ > + NL802154_CMD_NEW_SEC_DEVKEY, > + NL802154_CMD_DEL_SEC_DEVKEY, > + NL802154_CMD_GET_SEC_LEVEL, /* can dump */ > + NL802154_CMD_NEW_SEC_LEVEL, > + NL802154_CMD_DEL_SEC_LEVEL, > +#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ > + > /* used to define NL802154_CMD_MAX below */ > __NL802154_CMD_AFTER_LAST, > NL802154_CMD_MAX = __NL802154_CMD_AFTER_LAST - 1 > @@ -110,6 +126,18 @@ enum nl802154_attrs { > > /* add attributes here, update the policy in nl802154.c */ > > +#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL > + NL802154_ATTR_SEC_ENABLED, > + NL802154_ATTR_SEC_OUT_LEVEL, > + NL802154_ATTR_SEC_OUT_KEY_ID, > + NL802154_ATTR_SEC_FRAME_COUNTER, > + > + NL802154_ATTR_SEC_LEVEL, > + NL802154_ATTR_SEC_DEVICE, > + NL802154_ATTR_SEC_DEVKEY, > + NL802154_ATTR_SEC_KEY, > +#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ > + > __NL802154_ATTR_AFTER_LAST, > NL802154_ATTR_MAX = __NL802154_ATTR_AFTER_LAST - 1 > }; > @@ -247,4 +275,167 @@ enum nl802154_supported_bool_states { > NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 > }; > > +#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL > + > +enum nl802154_dev_addr_modes { > + NL802154_DEV_ADDR_NONE, > + __NL802154_DEV_ADDR_INVALID, > + NL802154_DEV_ADDR_SHORT, > + NL802154_DEV_ADDR_EXTENDED, > + > + /* keep last */ > + __NL802154_DEV_ADDR_AFTER_LAST, Hmm, why bother with AFTER_LAST here and not just use ADDR_MAX as sentinal for this enum? Looks redundant to me. > + NL802154_DEV_ADDR_MAX = __NL802154_DEV_ADDR_AFTER_LAST - 1 > +}; > + > +enum nl802154_dev_addr_attrs { > + NL802154_DEV_ADDR_ATTR_UNSPEC, > + > + NL802154_DEV_ADDR_ATTR_PAN_ID, > + NL802154_DEV_ADDR_ATTR_MODE, > + NL802154_DEV_ADDR_ATTR_SHORT, > + NL802154_DEV_ADDR_ATTR_EXTENDED, > + > + /* keep last */ > + __NL802154_DEV_ADDR_ATTR_AFTER_LAST, > + NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1 Same as above > +}; > + > +enum nl802154_key_id_modes { > + NL802154_KEY_ID_MODE_IMPLICIT, > + NL802154_KEY_ID_MODE_INDEX, > + NL802154_KEY_ID_MODE_INDEX_SHORT, > + NL802154_KEY_ID_MODE_INDEX_EXTENDED, > + > + /* keep last */ > + __NL802154_KEY_ID_MODE_AFTER_LAST, > + NL802154_KEY_ID_MODE_MAX = __NL802154_KEY_ID_MODE_AFTER_LAST - 1 Same as above. > +}; > + > +enum nl802154_key_id_attrs { > + NL802154_KEY_ID_ATTR_UNSPEC, > + > + NL802154_KEY_ID_ATTR_MODE, > + NL802154_KEY_ID_ATTR_INDEX, > + NL802154_KEY_ID_ATTR_IMPLICIT, > + NL802154_KEY_ID_ATTR_SOURCE_SHORT, > + NL802154_KEY_ID_ATTR_SOURCE_EXTENDED, > + > + /* keep last */ > + __NL802154_KEY_ID_ATTR_AFTER_LAST, > + NL802154_KEY_ID_ATTR_MAX = __NL802154_KEY_ID_ATTR_AFTER_LAST - 1 Above > +}; > + > +enum nl802154_seclevels { > + NL802154_SECLEVEL_NONE, > + NL802154_SECLEVEL_MIC32, > + NL802154_SECLEVEL_MIC64, > + NL802154_SECLEVEL_MIC128, > + NL802154_SECLEVEL_ENC, > + NL802154_SECLEVEL_ENC_MIC32, > + NL802154_SECLEVEL_ENC_MIC64, > + NL802154_SECLEVEL_ENC_MIC128, > + > + /* keep last */ > + __NL802154_SECLEVEL_AFTER_LAST, > + NL802154_SECLEVEL_MAX = __NL802154_SECLEVEL_AFTER_LAST - 1 Above > +}; > + > +enum nl802154_frames { > + NL802154_FRAME_BEACON, > + NL802154_FRAME_DATA, > + NL802154_FRAME_ACK, > + NL802154_FRAME_CMD, > + > + /* keep last */ > + __NL802154_FRAME_AFTER_LAST, > + NL802154_FRAME_MAX = __NL802154_FRAME_AFTER_LAST - 1 Above > +}; > + > +enum nl802154_cmd_frames { > + __NL802154_CMD_FRAME_INVALID, > + NL802154_CMD_FRAME_ASSOC_REQUEST, > + NL802154_CMD_FRAME_ASSOC_RESPONSE, > + NL802154_CMD_FRAME_DISASSOC_NOTIFY, > + NL802154_CMD_FRAME_DATA_REQUEST, > + NL802154_CMD_FRAME_PAN_ID_CONFLICT_NOTIFY, > + NL802154_CMD_FRAME_ORPHAN_NOTIFY, > + NL802154_CMD_FRAME_BEACON_REQUEST, > + NL802154_CMD_FRAME_COORD_REALIGNMENT, > + NL802154_CMD_FRAME_GTS_REQUEST, > + > + /* keep last */ > + __NL802154_CMD_FRAME_AFTER_LAST, > + NL802154_CMD_FRAME_MAX = __NL802154_CMD_FRAME_AFTER_LAST - 1 Above, and for all other below. > +}; > + > +enum nl802154_seclevel_attrs { > + NL802154_SECLEVEL_ATTR_UNSPEC, > + > + NL802154_SECLEVEL_ATTR_LEVELS, > + NL802154_SECLEVEL_ATTR_FRAME, > + NL802154_SECLEVEL_ATTR_CMD_FRAME, > + NL802154_SECLEVEL_ATTR_DEV_OVERRIDE, > + > + /* keep last */ > + __NL802154_SECLEVEL_ATTR_AFTER_LAST, > + NL802154_SECLEVEL_ATTR_MAX = __NL802154_SECLEVEL_ATTR_AFTER_LAST - 1 > +}; > + > +/* TODO what is this? couldn't find in mib */ > +enum { > + NL802154_DEVKEY_IGNORE, > + NL802154_DEVKEY_RESTRICT, > + NL802154_DEVKEY_RECORD, > + > + /* keep last */ > + __NL802154_DEVKEY_AFTER_LAST, > + NL802154_DEVKEY_MAX = __NL802154_DEVKEY_AFTER_LAST - 1 > +}; > + > +enum nl802154_dev { > + NL802154_DEV_ATTR_UNSPEC, > + > + NL802154_DEV_ATTR_FRAME_COUNTER, > + NL802154_DEV_ATTR_PAN_ID, > + NL802154_DEV_ATTR_SHORT_ADDR, > + NL802154_DEV_ATTR_EXTENDED_ADDR, > + NL802154_DEV_ATTR_SECLEVEL_EXEMPT, > + NL802154_DEV_ATTR_KEY_MODE, > + > + /* keep last */ > + __NL802154_DEV_ATTR_AFTER_LAST, > + NL802154_DEV_ATTR_MAX = __NL802154_DEV_ATTR_AFTER_LAST - 1 > +}; > + > +enum nl802154_devkey { > + NL802154_DEVKEY_ATTR_UNSPEC, > + > + NL802154_DEVKEY_ATTR_FRAME_COUNTER, > + NL802154_DEVKEY_ATTR_EXTENDED_ADDR, > + NL802154_DEVKEY_ATTR_ID, > + > + /* keep last */ > + __NL802154_DEVKEY_ATTR_AFTER_LAST, > + NL802154_DEVKEY_ATTR_MAX = __NL802154_DEVKEY_ATTR_AFTER_LAST - 1 > +}; > + > +enum nl802154_key { > + NL802154_KEY_ATTR_UNSPEC, > + > + NL802154_KEY_ATTR_ID, > + NL802154_KEY_ATTR_USAGE_FRAMES, > + NL802154_KEY_ATTR_USAGE_CMDS, > + NL802154_KEY_ATTR_BYTES, > + > + /* keep last */ > + __NL802154_KEY_ATTR_AFTER_LAST, > + NL802154_KEY_ATTR_MAX = __NL802154_KEY_ATTR_AFTER_LAST - 1 > +}; > + > +#define NL802154_KEY_SIZE 16 > +#define NL802154_CMD_FRAME_NR_IDS 256 > + > +#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ > + > #endif /* __NL802154_H */ > diff --git a/src/security.c b/src/security.c > new file mode 100644 > index 0000000..3928dee > --- /dev/null > +++ b/src/security.c > @@ -0,0 +1,1118 @@ > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > +#include "nl_extras.h" > +#define CONFIG_IEEE802154_NL802154_EXPERIMENTAL > +#include "nl802154.h" > +#include "iwpan.h" > + > +static int handle_security_set(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + unsigned long enabled; > + char *end; > + > + if (argc < 1) > + return 1; > + > + /* enabled */ > + enabled = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (enabled > UINT8_MAX) > + return 1; > + > + NLA_PUT_U8(msg, NL802154_ATTR_SEC_ENABLED, enabled); > + > + return 0; > + > +nla_put_failure: > + return -ENOBUFS; > +} > +COMMAND(set, security, "<1|0>", NL802154_CMD_SET_SEC_PARAMS, 0, CIB_NETDEV, > + handle_security_set, NULL); > + > +static int handle_parse_key_id(struct nl_msg *msg, int attrtype, > + int *argc, char ***argv) > +{ > + struct nl_msg *key_id_msg, *dev_addr_msg = NULL; > + unsigned long key_mode, dev_addr_mode, short_addr, pan_id, index; > + unsigned long long extended_addr; > + char *end; > + > + if ((*argc) < 1) > + return 1; > + > + /* key_mode */ > + key_mode = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + (*argc)--; > + (*argv)++; > + > + switch (key_mode) { > + case NL802154_KEY_ID_MODE_IMPLICIT: > + if ((*argc) < 2) > + return 1; > + > + /* pan_id */ > + pan_id = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (pan_id > UINT16_MAX) > + return 1; > + > + (*argc)--; > + (*argv)++; > + > + /* dev_addr_mode */ > + dev_addr_mode = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + (*argc)--; > + (*argv)++; > + > + switch (dev_addr_mode) { > + case NL802154_DEV_ADDR_SHORT: > + if ((*argc) < 1) > + return 1; > + > + /* dev_addr_short */ > + short_addr = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (short_addr > UINT16_MAX) > + return 1; > + break; > + case NL802154_DEV_ADDR_EXTENDED: > + if ((*argc) < 1) > + return 1; > + > + /* dev_addr_short */ > + extended_addr = strtoull((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + break; > + default: > + return 1; > + } > + > + key_id_msg = nlmsg_alloc(); > + if (!key_id_msg) > + return -ENOMEM; > + > + dev_addr_msg = nlmsg_alloc(); > + if (!dev_addr_msg) > + return -ENOMEM; > + > + NLA_PUT_U16(dev_addr_msg, NL802154_DEV_ADDR_ATTR_PAN_ID, pan_id); > + NLA_PUT_U32(dev_addr_msg, NL802154_DEV_ADDR_ATTR_MODE, dev_addr_mode); > + NLA_PUT_U16(dev_addr_msg, NL802154_DEV_ADDR_ATTR_SHORT, htole16(short_addr)); > + NLA_PUT_U64(dev_addr_msg, NL802154_DEV_ADDR_ATTR_EXTENDED, htole64(extended_addr)); > + > + nla_put_nested(key_id_msg, NL802154_KEY_ID_ATTR_IMPLICIT, dev_addr_msg); > + > + nlmsg_free(dev_addr_msg); > + dev_addr_msg = NULL; > + > + break; > + case NL802154_KEY_ID_MODE_INDEX: > + if ((*argc) < 1) > + return 1; > + > + /* index */ > + index = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (index > UINT8_MAX) > + return 1; > + > + key_id_msg = nlmsg_alloc(); > + if (!key_id_msg) > + return -ENOMEM; > + > + NLA_PUT_U8(key_id_msg, NL802154_KEY_ID_ATTR_INDEX, index); > + break; > + case NL802154_KEY_ID_MODE_INDEX_SHORT: > + if ((*argc) < 2) > + return 1; > + > + /* index */ > + index = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (index > UINT8_MAX) > + return 1; > + > + (*argc)--; > + (*argv)++; > + > + /* source_short */ > + short_addr = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + key_id_msg = nlmsg_alloc(); > + if (!key_id_msg) > + return -ENOMEM; > + > + NLA_PUT_U8(key_id_msg, NL802154_KEY_ID_ATTR_INDEX, index); > + NLA_PUT_U32(key_id_msg, NL802154_KEY_ID_ATTR_SOURCE_SHORT, > + htole32(short_addr)); > + break; > + case NL802154_KEY_ID_MODE_INDEX_EXTENDED: > + if ((*argc) < 2) > + return 1; > + > + /* index */ > + index = strtoul((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (index > UINT8_MAX) > + return 1; > + > + (*argc)--; > + (*argv)++; > + > + /* source_extended */ > + extended_addr = strtoull((*argv)[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + key_id_msg = nlmsg_alloc(); > + if (!key_id_msg) > + return -ENOMEM; > + > + NLA_PUT_U8(key_id_msg, NL802154_KEY_ID_ATTR_INDEX, index); > + NLA_PUT_U64(key_id_msg, NL802154_KEY_ID_ATTR_SOURCE_EXTENDED, > + htole64(extended_addr)); > + break; > + default: > + return 1; > + } > + > + NLA_PUT_U32(key_id_msg, NL802154_KEY_ID_ATTR_MODE, key_mode); > + nla_put_nested(msg, attrtype, key_id_msg); > + > + nlmsg_free(key_id_msg); > + > + return 0; > + > +nla_put_failure: > + if (!dev_addr_msg) > + nlmsg_free(dev_addr_msg); > + > + nlmsg_free(key_id_msg); > + return -ENOBUFS; > +} > + > +static int handle_out_key_id_set(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + return handle_parse_key_id(msg, NL802154_ATTR_SEC_OUT_KEY_ID, &argc, &argv); > + > +} > +COMMAND(set, out_key_id, > + "<0 <2 |3 >>|" > + "<1 >|" > + "<2 >|" > + "<3 >", What are these extra >>| for ? > + NL802154_CMD_SET_SEC_PARAMS, 0, CIB_NETDEV, > + handle_out_key_id_set, NULL); > + > +static int handle_out_seclevel_set(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + unsigned long seclevel; > + char *end; > + > + if (argc < 1) > + return 1; > + > + /* seclevel */ > + seclevel = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + NLA_PUT_U32(msg, NL802154_ATTR_SEC_OUT_LEVEL, seclevel); > + > + return 0; > + > +nla_put_failure: > + return -ENOBUFS; > +} > +COMMAND(set, out_level, "", NL802154_CMD_SET_SEC_PARAMS, 0, CIB_NETDEV, > + handle_out_seclevel_set, NULL); > + > +static int handle_frame_counter_set(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + unsigned long frame_counter; > + char *end; > + > + /* frame_counter */ This command and the other above (index, etc) which just state the variable name below are not really needed as they give no extra information imho. > + frame_counter = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + NLA_PUT_U32(msg, NL802154_ATTR_SEC_FRAME_COUNTER, htobe32(frame_counter)); > + > + return 0; > + > +nla_put_failure: > + return -ENOBUFS; > +} > +COMMAND(set, frame_counter, "", NL802154_CMD_SET_SEC_PARAMS, 0, CIB_NETDEV, > + handle_frame_counter_set, NULL); > + > +SECTION(seclevel); > + > +static int print_seclevel_handler(struct nl_msg *msg, void *arg) > +{ > + struct nlattr *tb[NL802154_ATTR_MAX + 1]; > + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); > + > + nla_parse(tb, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), > + genlmsg_attrlen(gnlh, 0), NULL); > + > + if (tb[NL802154_ATTR_SEC_LEVEL]) { > + struct nlattr *tb_seclevel[NL802154_SECLEVEL_ATTR_MAX + 1]; > + static struct nla_policy seclevel_policy[NL802154_SECLEVEL_ATTR_MAX + 1] = { > + [NL802154_SECLEVEL_ATTR_LEVELS] = { .type = NLA_U32 }, > + [NL802154_SECLEVEL_ATTR_FRAME] = { .type = NLA_U32 }, > + [NL802154_SECLEVEL_ATTR_CMD_FRAME] = { .type = NLA_U32 }, > + [NL802154_SECLEVEL_ATTR_DEV_OVERRIDE] = { .type = NLA_U8 }, > + }; > + > + if (nla_parse_nested(tb_seclevel, NL802154_SECLEVEL_ATTR_MAX, > + tb[NL802154_ATTR_SEC_LEVEL], > + seclevel_policy)) { > + fprintf(stderr, "failed to parse nested attributes!\n"); > + return NL_SKIP; > + } > + > + printf("iwpan dev $WPAN_DEV seclevel add "); > + > + if (tb_seclevel[NL802154_SECLEVEL_ATTR_LEVELS]) > + printf("0x%02lx ", nla_get_u8(tb_seclevel[NL802154_SECLEVEL_ATTR_LEVELS])); > + if (tb_seclevel[NL802154_SECLEVEL_ATTR_FRAME]) > + printf("%d ", nla_get_u32(tb_seclevel[NL802154_SECLEVEL_ATTR_FRAME])); > + if (tb_seclevel[NL802154_SECLEVEL_ATTR_CMD_FRAME]) > + printf("%d ", nla_get_u32(tb_seclevel[NL802154_SECLEVEL_ATTR_CMD_FRAME])); > + if (tb_seclevel[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE]) > + printf("%d ", nla_get_u8(tb_seclevel[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE])); > + } > + > + printf("\n"); > + > + return NL_SKIP; > +} > + > +static int handle_seclevel_dump(struct nl802154_state *state, > + struct nl_cb *cb, > + struct nl_msg *msg, > + int argc, char **argv, > + enum id_input id) > +{ > + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_seclevel_handler, NULL); > + return 0; > +} > +COMMAND(seclevel, dump, NULL, > + NL802154_CMD_GET_SEC_LEVEL, NLM_F_DUMP, CIB_NETDEV, handle_seclevel_dump, > + NULL); > + > +static int handle_seclevel_add(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + struct nl_msg *seclevel_msg; > + unsigned long levels, frame, cmd_id, dev_override; > + char *end; > + > + if (argc < 1) > + return 1; > + > + /* levels */ > + levels = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* frame */ > + frame = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (frame == NL802154_FRAME_CMD) { > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* cmd_frame */ > + cmd_id = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + } > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* dev_override */ > + dev_override = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (dev_override > UINT8_MAX) > + return 1; > + > + seclevel_msg = nlmsg_alloc(); > + if (!seclevel_msg) > + return -ENOMEM; > + > + NLA_PUT_U32(seclevel_msg, NL802154_SECLEVEL_ATTR_LEVELS, levels); > + NLA_PUT_U32(seclevel_msg, NL802154_SECLEVEL_ATTR_FRAME, frame); > + if (frame == NL802154_FRAME_CMD) > + NLA_PUT_U32(seclevel_msg, NL802154_SECLEVEL_ATTR_CMD_FRAME, cmd_id); > + NLA_PUT_U8(seclevel_msg, NL802154_SECLEVEL_ATTR_DEV_OVERRIDE, dev_override); > + > + nla_put_nested(msg, NL802154_ATTR_SEC_LEVEL, seclevel_msg); > + nlmsg_free(seclevel_msg); > + > + return 0; > + > +nla_put_failure: > + nlmsg_free(seclevel_msg); > + return -ENOBUFS; > +} > +COMMAND(seclevel, add, " > ", NL802154_CMD_NEW_SEC_LEVEL, 0, CIB_NETDEV, > + handle_seclevel_add, NULL); > +COMMAND(seclevel, del, " > ", NL802154_CMD_DEL_SEC_LEVEL, 0, CIB_NETDEV, > + handle_seclevel_add, NULL); > + > +SECTION(device); > + > +static int print_device_handler(struct nl_msg *msg, void *arg) > +{ > + struct nlattr *tb[NL802154_ATTR_MAX + 1]; > + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); > + > + nla_parse(tb, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), > + genlmsg_attrlen(gnlh, 0), NULL); > + > + if (tb[NL802154_ATTR_SEC_DEVICE]) { > + struct nlattr *tb_device[NL802154_DEV_ATTR_MAX + 1]; > + static struct nla_policy device_policy[NL802154_DEV_ATTR_MAX + 1] = { > + [NL802154_DEV_ATTR_FRAME_COUNTER] = { NLA_U32 }, > + [NL802154_DEV_ATTR_PAN_ID] = { .type = NLA_U16 }, > + [NL802154_DEV_ATTR_SHORT_ADDR] = { .type = NLA_U16 }, > + [NL802154_DEV_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 }, > + [NL802154_DEV_ATTR_SECLEVEL_EXEMPT] = { NLA_U8 }, > + [NL802154_DEV_ATTR_KEY_MODE] = { NLA_U32 }, > + }; > + > + if (nla_parse_nested(tb_device, NL802154_DEV_ATTR_MAX, > + tb[NL802154_ATTR_SEC_DEVICE], > + device_policy)) { > + fprintf(stderr, "failed to parse nested attributes!\n"); > + return NL_SKIP; > + } > + > + printf("iwpan dev $WPAN_DEV device add "); > + > + if (tb_device[NL802154_DEV_ATTR_FRAME_COUNTER]) > + printf("0x%08lx ", nla_get_u32(tb_device[NL802154_DEV_ATTR_FRAME_COUNTER])); > + if (tb_device[NL802154_DEV_ATTR_PAN_ID]) > + printf("0x%04lx ", le16toh(nla_get_u16(tb_device[NL802154_DEV_ATTR_PAN_ID]))); > + if (tb_device[NL802154_DEV_ATTR_SHORT_ADDR]) > + printf("0x%04lx ", le16toh(nla_get_u16(tb_device[NL802154_DEV_ATTR_SHORT_ADDR]))); > + if (tb_device[NL802154_DEV_ATTR_EXTENDED_ADDR]) > + printf("0x%016" PRIx64 " ", le64toh(nla_get_u64(tb_device[NL802154_DEV_ATTR_EXTENDED_ADDR]))); > + if (tb_device[NL802154_DEV_ATTR_SECLEVEL_EXEMPT]) > + printf("%d ", nla_get_u8(tb_device[NL802154_DEV_ATTR_SECLEVEL_EXEMPT])); > + if (tb_device[NL802154_DEV_ATTR_KEY_MODE]) > + printf("%d ", nla_get_u32(tb_device[NL802154_DEV_ATTR_KEY_MODE])); > + } > + > + printf("\n"); > + > + return NL_SKIP; > +} > + > +static int handle_device_dump(struct nl802154_state *state, > + struct nl_cb *cb, > + struct nl_msg *msg, > + int argc, char **argv, > + enum id_input id) > +{ > + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_device_handler, NULL); > + return 0; > +} > +COMMAND(device, dump, NULL, > + NL802154_CMD_GET_SEC_DEV, NLM_F_DUMP, CIB_NETDEV, handle_device_dump, > + NULL); > + > +static int handle_device_add(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + struct nl_msg *device_msg; > + unsigned long long extended_addr; > + unsigned long frame_counter, pan_id, short_addr, > + seclevel_exempt, key_mode; > + char *end; > + > + if (argc < 1) > + return 1; > + > + /* frame_counter */ > + frame_counter = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* pan_id */ > + pan_id = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (pan_id > UINT16_MAX) > + return 1; > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* short_addr */ > + short_addr = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (short_addr > UINT16_MAX) > + return 1; > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* extended_addr */ > + extended_addr = strtoull(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* seclevel_exempt */ > + seclevel_exempt = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + if (seclevel_exempt > UINT8_MAX) > + return 1; > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* key_mode */ > + key_mode = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + device_msg = nlmsg_alloc(); > + if (!device_msg) > + return -ENOMEM; > + > + NLA_PUT_U32(device_msg, NL802154_DEV_ATTR_FRAME_COUNTER, frame_counter); > + NLA_PUT_U16(device_msg, NL802154_DEV_ATTR_PAN_ID, htole16(pan_id)); > + NLA_PUT_U16(device_msg, NL802154_DEV_ATTR_SHORT_ADDR, htole16(short_addr)); > + NLA_PUT_U64(device_msg, NL802154_DEV_ATTR_EXTENDED_ADDR, htole64(extended_addr)); > + NLA_PUT_U8(device_msg, NL802154_DEV_ATTR_SECLEVEL_EXEMPT, seclevel_exempt); > + NLA_PUT_U32(device_msg, NL802154_DEV_ATTR_KEY_MODE, key_mode); > + > + nla_put_nested(msg, NL802154_ATTR_SEC_DEVICE, device_msg); > + nlmsg_free(device_msg); > + > + return 0; > + > +nla_put_failure: > + nlmsg_free(device_msg); > + return -ENOBUFS; > +} > +COMMAND(device, add, " ", > + NL802154_CMD_NEW_SEC_DEV, 0, CIB_NETDEV, handle_device_add, NULL); > + > +static int handle_device_del(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + struct nl_msg *device_msg; > + unsigned long long extended_addr; > + char *end; > + > + if (argc < 1) > + return 1; > + > + /* extended_addr */ > + extended_addr = strtoull(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + device_msg = nlmsg_alloc(); > + if (!device_msg) > + return -ENOMEM; > + > + NLA_PUT_U64(device_msg, NL802154_DEV_ATTR_EXTENDED_ADDR, htole64(extended_addr)); > + > + nla_put_nested(msg, NL802154_ATTR_SEC_DEVICE, device_msg); > + nlmsg_free(device_msg); > + > + return 0; > + > +nla_put_failure: > + nlmsg_free(device_msg); > + return -ENOBUFS; > +} > +COMMAND(device, del, "", > + NL802154_CMD_DEL_SEC_DEV, 0, CIB_NETDEV, handle_device_del, NULL); > + > +SECTION(devkey); > + > +static int print_key_id(struct nlattr *tb) { > + struct nlattr *tb_key_id[NL802154_KEY_ID_ATTR_MAX + 1]; > + static struct nla_policy key_id_policy[NL802154_KEY_ID_ATTR_MAX + 1] = { > + [NL802154_KEY_ID_ATTR_MODE] = { .type = NLA_U32 }, > + [NL802154_KEY_ID_ATTR_INDEX] = { .type = NLA_U8 }, > + [NL802154_KEY_ID_ATTR_IMPLICIT] = { .type = NLA_NESTED }, > + [NL802154_KEY_ID_ATTR_SOURCE_SHORT] = { .type = NLA_U32 }, > + [NL802154_KEY_ID_ATTR_SOURCE_EXTENDED] = { .type = NLA_U64 }, > + }; > + > + nla_parse_nested(tb_key_id, NL802154_KEY_ID_ATTR_MAX, tb, key_id_policy); > + > + if (tb_key_id[NL802154_KEY_ID_ATTR_MODE]) { > + enum nl802154_key_id_modes key_id_mode; > + > + key_id_mode = nla_get_u32(tb_key_id[NL802154_KEY_ID_ATTR_MODE]); > + printf("%d ", key_id_mode); > + switch (key_id_mode) { > + case NL802154_KEY_ID_MODE_IMPLICIT: > + if (tb_key_id[NL802154_KEY_ID_ATTR_IMPLICIT]) { > + struct nlattr *tb_dev_addr[NL802154_DEV_ADDR_ATTR_MAX + 1]; > + static struct nla_policy dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { > + [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, > + [NL802154_DEV_ADDR_ATTR_MODE] = { .type = NLA_U32 }, > + [NL802154_DEV_ADDR_ATTR_SHORT] = { .type = NLA_U16 }, > + [NL802154_DEV_ADDR_ATTR_EXTENDED] = { .type = NLA_U64 }, > + }; > + > + nla_parse_nested(tb_dev_addr, NL802154_DEV_ADDR_ATTR_MAX, > + tb_key_id[NL802154_KEY_ID_ATTR_IMPLICIT], > + dev_addr_policy); > + > + if (tb_dev_addr[NL802154_DEV_ADDR_ATTR_PAN_ID]) > + printf("0x%04x ", > + le16toh(nla_get_u16(tb_dev_addr[NL802154_DEV_ADDR_ATTR_PAN_ID]))); > + > + if (tb_dev_addr[NL802154_DEV_ADDR_ATTR_MODE]) { > + enum nl802154_dev_addr_modes dev_addr_mode; > + dev_addr_mode = nla_get_u32(tb_dev_addr[NL802154_DEV_ADDR_ATTR_MODE]); > + printf("%d ", dev_addr_mode); > + switch (dev_addr_mode) { > + case NL802154_DEV_ADDR_SHORT: > + printf("0x%04x ", > + le16toh(nla_get_u16(tb_dev_addr[NL802154_DEV_ADDR_ATTR_SHORT]))); > + break; > + case NL802154_DEV_ADDR_EXTENDED: > + printf("0x%016" PRIx64 " ", > + le64toh(nla_get_u64(tb_dev_addr[NL802154_DEV_ADDR_ATTR_SHORT]))); > + break; > + default: > + /* TODO error handling */ > + break; > + } > + } > + } > + break; > + case NL802154_KEY_ID_MODE_INDEX: > + if (tb_key_id[NL802154_KEY_ID_ATTR_INDEX]) > + printf("0x%02x ", > + nla_get_u8(tb_key_id[NL802154_KEY_ID_ATTR_INDEX])); > + break; > + case NL802154_KEY_ID_MODE_INDEX_SHORT: > + if (tb_key_id[NL802154_KEY_ID_ATTR_INDEX]) > + printf("0x%02x ", > + nla_get_u8(tb_key_id[NL802154_KEY_ID_ATTR_INDEX])); > + > + if (tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_SHORT]) > + printf("0x%08lx ", > + le32toh(nla_get_u32(tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_SHORT]))); > + break; > + case NL802154_KEY_ID_MODE_INDEX_EXTENDED: > + if (tb_key_id[NL802154_KEY_ID_ATTR_INDEX]) > + printf("0x%02x ", > + nla_get_u8(tb_key_id[NL802154_KEY_ID_ATTR_INDEX])); > + > + if (tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED]) > + printf("0x%016" PRIx64 " ", > + le64toh(nla_get_u64(tb_key_id[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED]))); > + break; > + default: > + /* TODO error handling */ > + return 0; > + } > + } > + > + return 0; > +} > + > +static int print_devkey_handler(struct nl_msg *msg, void *arg) > +{ > + struct nlattr *tb[NL802154_ATTR_MAX + 1]; > + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); > + > + nla_parse(tb, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), > + genlmsg_attrlen(gnlh, 0), NULL); > + > + if (tb[NL802154_ATTR_SEC_DEVKEY]) { > + struct nlattr *tb_devkey[NL802154_DEVKEY_ATTR_MAX + 1]; > + static struct nla_policy devkey_policy[NL802154_DEVKEY_ATTR_MAX + 1] = { > + [NL802154_DEVKEY_ATTR_FRAME_COUNTER] = { NLA_U32 }, > + [NL802154_DEVKEY_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 }, > + [NL802154_DEVKEY_ATTR_ID] = { .type = NLA_NESTED }, > + }; > + > + if (nla_parse_nested(tb_devkey, NL802154_DEVKEY_ATTR_MAX, > + tb[NL802154_ATTR_SEC_DEVKEY], > + devkey_policy)) { > + fprintf(stderr, "failed to parse nested attributes!\n"); > + return NL_SKIP; > + } > + > + printf("iwpan dev $WPAN_DEV devkey add "); > + > + if (tb_devkey[NL802154_DEV_ATTR_FRAME_COUNTER]) > + printf("0x%08lx ", nla_get_u32(tb_devkey[NL802154_DEVKEY_ATTR_FRAME_COUNTER])); > + if (tb_devkey[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]) > + printf("0x%016" PRIx64 " ", le64toh(nla_get_u64(tb_devkey[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]))); > + > + if (tb_devkey[NL802154_DEVKEY_ATTR_ID]) > + print_key_id(tb_devkey[NL802154_DEVKEY_ATTR_ID]); > + } > + > + printf("\n"); > + > + return NL_SKIP; > +} > + > +static int handle_devkey_dump(struct nl802154_state *state, > + struct nl_cb *cb, > + struct nl_msg *msg, > + int argc, char **argv, > + enum id_input id) > +{ > + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_devkey_handler, NULL); > + return 0; > +} > +COMMAND(devkey, dump, NULL, > + NL802154_CMD_GET_SEC_DEVKEY, NLM_F_DUMP, CIB_NETDEV, handle_devkey_dump, > + NULL); > + > +static int handle_devkey_add(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + struct nl_msg *devkey_msg = NULL; > + unsigned long long extended_addr; > + unsigned long frame_counter; > + char *end; > + int ret; > + > + if (argc < 1) > + return 1; > + > + /* frame_counter */ > + frame_counter = strtoul(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + argc--; > + argv++; > + > + if (argc < 1) > + return 1; > + > + /* extended_addr */ > + extended_addr = strtoull(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + argc--; > + argv++; > + > + devkey_msg = nlmsg_alloc(); > + if (!devkey_msg) > + return -ENOMEM; > + > + NLA_PUT_U32(devkey_msg, NL802154_DEVKEY_ATTR_FRAME_COUNTER, frame_counter); > + NLA_PUT_U64(devkey_msg, NL802154_DEVKEY_ATTR_EXTENDED_ADDR, htole64(extended_addr)); > + > + ret = handle_parse_key_id(devkey_msg, NL802154_DEVKEY_ATTR_ID, &argc, &argv); > + if (ret) { > + nlmsg_free(devkey_msg); > + return ret; > + } > + > + nla_put_nested(msg, NL802154_ATTR_SEC_DEVKEY, devkey_msg); > + nlmsg_free(devkey_msg); > + > + return 0; > + > +nla_put_failure: > + nlmsg_free(devkey_msg); > + return -ENOBUFS; > + > +} > +COMMAND(devkey, add, " " > + "<0 <2 |3 >>|" > + "<1 >|" > + "<2 >|" > + "<3 >", > + NL802154_CMD_NEW_SEC_DEVKEY, 0, CIB_NETDEV, handle_devkey_add, NULL); > + > +static int handle_devkey_del(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + struct nl_msg *devkey_msg = NULL; > + unsigned long long extended_addr; > + char *end; > + int ret; > + > + if (argc < 1) > + return 1; > + > + /* extended_addr */ > + extended_addr = strtoull(argv[0], &end, 0); > + if (*end != '\0') > + return 1; > + > + argc--; > + argv++; > + > + devkey_msg = nlmsg_alloc(); > + if (!devkey_msg) > + return -ENOMEM; > + > + NLA_PUT_U64(devkey_msg, NL802154_DEVKEY_ATTR_EXTENDED_ADDR, htole64(extended_addr)); > + > + ret = handle_parse_key_id(devkey_msg, NL802154_DEVKEY_ATTR_ID, &argc, &argv); > + if (ret) { > + nlmsg_free(devkey_msg); > + return ret; > + } > + > + nla_put_nested(msg, NL802154_ATTR_SEC_DEVKEY, devkey_msg); > + nlmsg_free(devkey_msg); > + > + return 0; > + > +nla_put_failure: > + nlmsg_free(devkey_msg); > + return -ENOBUFS; > + > +} > +COMMAND(devkey, del, " " > + "<0 <2 |3 >>|" > + "<1 >|" > + "<2 >|" > + "<3 >", > + NL802154_CMD_DEL_SEC_DEVKEY, 0, CIB_NETDEV, handle_devkey_del, NULL); > + > +SECTION(key); > + > +static void key_to_str(char *key, unsigned char *arg) > +{ > + int i, l; > + > + l = 0; > + for (i = 0; i < NL802154_KEY_SIZE ; i++) { > + if (i == 0) { > + sprintf(key+l, "%02x", arg[i]); > + l += 2; > + } else { > + sprintf(key+l, ":%02x", arg[i]); > + l += 3; > + } > + } > +} > + > +static int print_key_handler(struct nl_msg *msg, void *arg) > +{ > + struct nlattr *tb[NL802154_ATTR_MAX + 1]; > + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); > + > + nla_parse(tb, NL802154_ATTR_MAX, genlmsg_attrdata(gnlh, 0), > + genlmsg_attrlen(gnlh, 0), NULL); > + > + if (tb[NL802154_ATTR_SEC_KEY]) { > + struct nlattr *tb_key[NL802154_KEY_ATTR_MAX + 1]; > + static struct nla_policy key_policy[NL802154_KEY_ATTR_MAX + 1] = { > + [NL802154_KEY_ATTR_ID] = { NLA_NESTED }, > + [NL802154_KEY_ATTR_USAGE_FRAMES] = { NLA_U8 }, > + [NL802154_KEY_ATTR_USAGE_CMDS] = { .minlen = NL802154_CMD_FRAME_NR_IDS / 8 }, > + [NL802154_KEY_ATTR_BYTES] = { .minlen = NL802154_KEY_SIZE }, > + }; > + > + if (nla_parse_nested(tb_key, NL802154_KEY_ATTR_MAX, > + tb[NL802154_ATTR_SEC_KEY], > + key_policy)) { > + fprintf(stderr, "failed to parse nested attributes!\n"); > + return NL_SKIP; > + } > + > + printf("iwpan dev $WPAN_DEV key add "); > + > + if (tb_key[NL802154_KEY_ATTR_USAGE_FRAMES]) > + printf("0x%02x ", nla_get_u8(tb_key[NL802154_KEY_ATTR_USAGE_FRAMES])); > + > + if (tb_key[NL802154_KEY_ATTR_USAGE_CMDS]) { > + uint32_t cmds[NL802154_CMD_FRAME_NR_IDS / 32]; > + > + nla_memcpy(cmds, tb_key[NL802154_KEY_ATTR_USAGE_CMDS], > + NL802154_CMD_FRAME_NR_IDS / 8); > + printf("0x%08x ", cmds[7]); > + } > + > + if (tb_key[NL802154_KEY_ATTR_BYTES]) { > + uint8_t key[NL802154_KEY_SIZE]; > + char key_str[512] = ""; > + > + nla_memcpy(key, tb_key[NL802154_KEY_ATTR_BYTES], > + NL802154_KEY_SIZE); > + > + key_to_str(key_str, key); > + printf("%s ", key_str); > + } > + > + if (tb_key[NL802154_KEY_ATTR_ID]) > + print_key_id(tb_key[NL802154_KEY_ATTR_ID]); > + } > + > + printf("\n"); > + > + return NL_SKIP; > +} > + > +static int handle_key_dump(struct nl802154_state *state, > + struct nl_cb *cb, > + struct nl_msg *msg, > + int argc, char **argv, > + enum id_input id) > +{ > + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_key_handler, NULL); > + return 0; > +} > +COMMAND(key, dump, NULL, > + NL802154_CMD_GET_SEC_KEY, NLM_F_DUMP, CIB_NETDEV, handle_key_dump, > + NULL); > + > +#define BIT(x) (1 << (x)) > + > +static int str_to_key(unsigned char *key, char *arg) > +{ > + int i; > + > + for (i = 0; i < NL802154_KEY_SIZE; i++) { > + int temp; > + char *cp = strchr(arg, ':'); > + if (cp) { > + *cp = 0; > + cp++; > + } > + if (sscanf(arg, "%x", &temp) != 1) > + return -1; > + if (temp < 0 || temp > 255) > + return -1; > + > + key[i] = temp; > + if (!cp) > + break; > + arg = cp; > + } > + if (i < NL802154_KEY_SIZE - 1) > + return -1; > + > + return 0; > +} > + > +static int handle_key_add(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + struct nl_msg *key_msg = NULL; > + uint8_t key_bytes[NL802154_KEY_SIZE] = { }; > + uint32_t commands[NL802154_CMD_FRAME_NR_IDS / 32] = { }; > + unsigned long tmp; > + char *end; > + int ret, i; > + > + key_msg = nlmsg_alloc(); > + if (!key_msg) > + return -ENOMEM; > + > + if (argc < 1) { > + nlmsg_free(key_msg); > + return 1; > + } > + > + /* frame_types */ > + tmp = strtoul(argv[0], &end, 0); > + if (*end != '\0') { > + nlmsg_free(key_msg); > + return 1; > + } > + > + if (tmp > UINT8_MAX) { > + nlmsg_free(key_msg); > + return 1; > + } > + > + NLA_PUT_U8(key_msg, NL802154_KEY_ATTR_USAGE_FRAMES, tmp); > + > + argc--; > + argv++; > + > + if (tmp & BIT(NL802154_FRAME_CMD)) { > + if (argc < 1) { > + nlmsg_free(key_msg); > + return 1; > + } > + > + /* commands[7] */ > + commands[7] = strtoul(argv[0], &end, 0); > + if (*end != '\0') { > + nlmsg_free(key_msg); > + return 1; > + } > + > + NLA_PUT(key_msg, NL802154_KEY_ATTR_USAGE_CMDS, > + NL802154_CMD_FRAME_NR_IDS / 8, commands); > + > + argc--; > + argv++; > + } > + > + if (argc < 1) { > + nlmsg_free(key_msg); > + return 1; > + } > + > + str_to_key(key_bytes, argv[0]); > + > + NLA_PUT(key_msg, NL802154_KEY_ATTR_BYTES, NL802154_KEY_SIZE, key_bytes); > + > + argc--; > + argv++; > + > + ret = handle_parse_key_id(key_msg, NL802154_KEY_ATTR_ID, &argc, &argv); > + if (ret) { > + nlmsg_free(key_msg); > + return ret; > + } > + > + nla_put_nested(msg, NL802154_ATTR_SEC_KEY, key_msg); > + nlmsg_free(key_msg); > + > + return 0; > + > +nla_put_failure: > + nlmsg_free(key_msg); > + return -ENOBUFS; > + > +} > +COMMAND(key, add, ">> > " > + "<0 <2 |3 >>|" > + "<1 >|" > + "<2 >|" > + "<3 >", > + NL802154_CMD_NEW_SEC_KEY, 0, CIB_NETDEV, handle_key_add, NULL); > + > +static int handle_key_del(struct nl802154_state *state, struct nl_cb *cb, > + struct nl_msg *msg, int argc, char **argv, > + enum id_input id) > +{ > + struct nl_msg *key_msg = NULL; > + int ret; > + > + key_msg = nlmsg_alloc(); > + if (!key_msg) > + return -ENOMEM; > + > + ret = handle_parse_key_id(key_msg, NL802154_KEY_ATTR_ID, &argc, &argv); > + if (ret) { > + nlmsg_free(key_msg); > + return ret; > + } > + > + nla_put_nested(msg, NL802154_ATTR_SEC_KEY, key_msg); > + nlmsg_free(key_msg); > + > + return 0; > + > +nla_put_failure: > + nlmsg_free(key_msg); > + return -ENOBUFS; > + > +} > +COMMAND(key, del, > + "<0 <2 |3 >>|" > + "<1 >|" > + "<2 >|" > + "<3 >", > + NL802154_CMD_DEL_SEC_KEY, 0, CIB_NETDEV, handle_key_del, NULL); regards Stefan Schmidt