This patch adds support for dumping phy capabilities by running iwpan list, which printout something like: capabilities: iftypes: node,monitor channels: page 0: 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 tx_powers: 3,2,1,0,-1,-2,-3,-4,-5,-7,-9,-12,-17 cca_ed_levels: -91,-89,-87,-85,-83,-81,-79,-77,-75,-73,-71,-69,-67,-65,-63,-61 cca_modes: 1,2,3 cca_opts: 0(cca_mode: 3),1(cca_mode: 3) min_be: 0,1,2,3,4,5,6,7,8 max_be: 3,4,5,6,7,8 csma_backoffs: 0,1,2,3,4,5 frame_retries: -1,0,1,2,3,4,5,6,7 lbt: false Signed-off-by: Alexander Aring <alex.aring@xxxxxxxxx> --- src/info.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/iwpan.h | 2 + src/nl802154.h | 79 +++++++++++++++++++++++++ src/nl_extras.h | 5 ++ 4 files changed, 261 insertions(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index e155470..636df49 100644 --- a/src/info.c +++ b/src/info.c @@ -12,11 +12,22 @@ #include "nl_extras.h" #include "iwpan.h" +static void print_minmax_handler(int min, int max) +{ + int i; + + for (i = min; i <= max; i++) + printf("%d,", i); + + /* TODO */ + printf("\b \n"); +} + static int print_phy_handler(struct nl_msg *msg, void *arg) { struct nlattr *tb_msg[NL802154_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); - int rem_page, i; + int rem_page, i, ret; int64_t phy_id = -1; bool print_name = true; struct nlattr *nl_page; @@ -33,6 +44,7 @@ static int print_phy_handler(struct nl_msg *msg, void *arg) if (print_name && tb_msg[NL802154_ATTR_WPAN_PHY_NAME]) printf("wpan_phy %s\n", nla_get_string(tb_msg[NL802154_ATTR_WPAN_PHY_NAME])); + /* TODO remove this handling it's deprecated */ if (tb_msg[NL802154_ATTR_CHANNELS_SUPPORTED]) { unsigned char page = 0; unsigned long channel; @@ -85,6 +97,168 @@ static int print_phy_handler(struct nl_msg *msg, void *arg) if (tb_msg[NL802154_ATTR_TX_POWER]) printf("tx_power: %d\n", nla_get_s8(tb_msg[NL802154_ATTR_TX_POWER])); + if (tb_msg[NL802154_ATTR_WPAN_PHY_CAPS]) { + struct nlattr *tb_caps[NL802154_CAP_ATTR_MAX + 1]; + /* TODO fix netlink lib that we can use NLA_S32 here + * see function validate_nla line if (pt->type > NLA_TYPE_MAX) */ + static struct nla_policy caps_policy[NL802154_CAP_ATTR_MAX + 1] = { + [NL802154_CAP_ATTR_CHANNELS] = { .type = NLA_NESTED }, + [NL802154_CAP_ATTR_TX_POWERS] = { .type = NLA_NESTED }, + [NL802154_CAP_ATTR_CCA_ED_LEVELS] = { .type = NLA_NESTED }, + [NL802154_CAP_ATTR_CCA_MODES] = { .type = NLA_NESTED }, + [NL802154_CAP_ATTR_CCA_OPTS] = { .type = NLA_NESTED }, + [NL802154_CAP_ATTR_MIN_MINBE] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_MAX_MINBE] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_MIN_MAXBE] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_MAX_MAXBE] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_MIN_FRAME_RETRIES] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_U8 }, + [NL802154_CAP_ATTR_IFTYPES] = { .type = NLA_NESTED }, + [NL802154_CAP_ATTR_LBT] = { .type = NLA_U32 }, + }; + + printf("capabilities:\n"); + + ret = nla_parse_nested(tb_caps, NL802154_CAP_ATTR_MAX, + tb_msg[NL802154_ATTR_WPAN_PHY_CAPS], + caps_policy); + if (ret) { + printf("failed to parse caps\n"); + return -EIO; + } + + if (tb_caps[NL802154_CAP_ATTR_IFTYPES]) { + struct nlattr *nl_iftypes; + int rem_iftypes; + printf("\tiftypes: "); + nla_for_each_nested(nl_iftypes, + tb_caps[NL802154_CAP_ATTR_IFTYPES], + rem_iftypes) + printf("%s,", iftype_name(nla_type(nl_iftypes))); + /* TODO */ + printf("\b \n"); + } + + if (tb_msg[NL802154_CAP_ATTR_CHANNELS]) { + int rem_pages; + struct nlattr *nl_pages; + printf("\tchannels:\n"); + nla_for_each_nested(nl_pages, tb_caps[NL802154_CAP_ATTR_CHANNELS], + rem_pages) { + int rem_channels; + struct nlattr *nl_channels; + printf("\t\tpage %d: ", nla_type(nl_pages)); + nla_for_each_nested(nl_channels, nl_pages, rem_channels) + printf("%d,", nla_type(nl_channels)); + /* TODO hack use sprintf here */ + printf("\b \b\n"); + } + } + + if (tb_caps[NL802154_CAP_ATTR_TX_POWERS]) { + int rem_pwrs; + struct nlattr *nl_pwrs; + + printf("\ttx_powers: "); + nla_for_each_nested(nl_pwrs, tb_caps[NL802154_CAP_ATTR_TX_POWERS], rem_pwrs) + printf("%d,", nla_get_s8(nl_pwrs)); + /* TODO */ + printf("\b \n"); + } + + if (tb_caps[NL802154_CAP_ATTR_CCA_ED_LEVELS]) { + int rem_levels; + struct nlattr *nl_levels; + + printf("\tcca_ed_levels: "); + nla_for_each_nested(nl_levels, tb_caps[NL802154_CAP_ATTR_CCA_ED_LEVELS], rem_levels) + printf("%d,", nla_get_s32(nl_levels)); + /* TODO */ + printf("\b \n"); + } + + if (tb_caps[NL802154_CAP_ATTR_CCA_MODES]) { + struct nlattr *nl_cca_modes; + int rem_cca_modes; + printf("\tcca_modes: "); + nla_for_each_nested(nl_cca_modes, + tb_caps[NL802154_CAP_ATTR_CCA_MODES], + rem_cca_modes) + printf("%d,", nla_type(nl_cca_modes)); + /* TODO */ + printf("\b \n"); + } + + if (tb_caps[NL802154_CAP_ATTR_CCA_OPTS]) { + struct nlattr *nl_cca_opts; + int rem_cca_opts; + + printf("\tcca_opts: "); + nla_for_each_nested(nl_cca_opts, + tb_caps[NL802154_CAP_ATTR_CCA_OPTS], + rem_cca_opts) { + printf("%d", nla_type(nl_cca_opts)); + switch (nla_type(nl_cca_opts)) { + case NL802154_CCA_OPT_ENERGY_CARRIER_AND: + case NL802154_CCA_OPT_ENERGY_CARRIER_OR: + printf("(cca_mode: 3),"); + break; + default: + printf("unkown\n"); + break; + } + } + /* TODO */ + printf("\b \n"); + } + + if (tb_caps[NL802154_CAP_ATTR_MIN_MINBE] && + tb_caps[NL802154_CAP_ATTR_MAX_MINBE] && + tb_caps[NL802154_CAP_ATTR_MIN_MAXBE] && + tb_caps[NL802154_CAP_ATTR_MAX_MAXBE]) { + printf("\tmin_be: "); + print_minmax_handler(nla_get_u8(tb_caps[NL802154_CAP_ATTR_MIN_MINBE]), + nla_get_u8(tb_caps[NL802154_CAP_ATTR_MAX_MINBE])); + printf("\tmax_be: "); + print_minmax_handler(nla_get_u8(tb_caps[NL802154_CAP_ATTR_MIN_MAXBE]), + nla_get_u8(tb_caps[NL802154_CAP_ATTR_MAX_MAXBE])); + } + + if (tb_caps[NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS] && + tb_caps[NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS]) { + printf("\tcsma_backoffs: "); + print_minmax_handler(nla_get_u8(tb_caps[NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS]), + nla_get_u8(tb_caps[NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS])); + } + + if (tb_caps[NL802154_CAP_ATTR_MIN_FRAME_RETRIES] && + tb_caps[NL802154_CAP_ATTR_MAX_FRAME_RETRIES]) { + printf("\tframe_retries: "); + print_minmax_handler(nla_get_s8(tb_caps[NL802154_CAP_ATTR_MIN_FRAME_RETRIES]), + nla_get_s8(tb_caps[NL802154_CAP_ATTR_MAX_FRAME_RETRIES])); + } + + if (tb_caps[NL802154_CAP_ATTR_LBT]) { + printf("\tlbt: "); + switch (nla_get_u32(tb_caps[NL802154_CAP_ATTR_LBT])) { + case NL802154_SUPPORTED_BOOL_FALSE: + printf("false\n"); + break; + case NL802154_SUPPORTED_BOOL_TRUE: + printf("true\n"); + break; + case NL802154_SUPPORTED_BOOL_BOTH: + printf("false,true\n"); + break; + default: + printf("unkown\n"); + break; + } + } + } + return 0; } diff --git a/src/iwpan.h b/src/iwpan.h index 867bb18..9e3f158 100644 --- a/src/iwpan.h +++ b/src/iwpan.h @@ -113,4 +113,6 @@ int handle_cmd(struct nl802154_state *state, enum id_input idby, DECLARE_SECTION(set); DECLARE_SECTION(get); +const char *iftype_name(enum nl802154_iftype iftype); + #endif /* __IWPAN_H */ diff --git a/src/nl802154.h b/src/nl802154.h index f8b5bc9..8c49714 100644 --- a/src/nl802154.h +++ b/src/nl802154.h @@ -100,6 +100,8 @@ enum nl802154_attrs { NL802154_ATTR_EXTENDED_ADDR, + NL802154_ATTR_WPAN_PHY_CAPS, + /* add attributes here, update the policy in nl802154.c */ __NL802154_ATTR_AFTER_LAST, @@ -120,6 +122,61 @@ enum nl802154_iftype { }; /** + * enum nl802154_wpan_phy_capability_attr - capability attributes + * + * @__NL802154_CAP_ATTR_INVALID: attribute number 0 is reserved + * @NL802154_CAP_ATTR_CHANNELS: a nested attribute for nl802154_channel_attr + * @NL802154_CAP_ATTR_TX_POWERS: a nested attribute for + * nl802154_wpan_phy_tx_power + * @NL802154_CAP_ATTR_MIN_CCA_ED_LEVEL: minimum value for cca_ed_level + * @NL802154_CAP_ATTR_MAX_CCA_ED_LEVEL: maxmimum value for cca_ed_level + * @NL802154_CAP_ATTR_CCA_MODES: nl802154_cca_modes flags + * @NL802154_CAP_ATTR_CCA_OPTS: nl802154_cca_opts flags + * @NL802154_CAP_ATTR_MIN_MINBE: minimum of minbe value + * @NL802154_CAP_ATTR_MAX_MINBE: maximum of minbe value + * @NL802154_CAP_ATTR_MIN_MAXBE: minimum of maxbe value + * @NL802154_CAP_ATTR_MAX_MINBE: maximum of maxbe value + * @NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS: minimum of csma backoff value + * @NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS: maximum of csma backoffs value + * @NL802154_CAP_ATTR_MIN_FRAME_RETRIES: minimum of frame retries value + * @NL802154_CAP_ATTR_MAX_FRAME_RETRIES: maximum of frame retries value + * @NL802154_CAP_ATTR_IFTYPES: nl802154_iftype flags + * @NL802154_CAP_ATTR_LBT: nl802154_supported_bool_states flags + * @NL802154_CAP_ATTR_MAX: highest cap attribute currently defined + * @__NL802154_CAP_ATTR_AFTER_LAST: internal use + */ +enum nl802154_capability_attr { + __NL802154_CAP_ATTR_INVALID, + + NL802154_CAP_ATTR_IFTYPES, + + NL802154_CAP_ATTR_CHANNELS, + NL802154_CAP_ATTR_TX_POWERS, + + NL802154_CAP_ATTR_CCA_ED_LEVELS, + NL802154_CAP_ATTR_CCA_MODES, + NL802154_CAP_ATTR_CCA_OPTS, + + NL802154_CAP_ATTR_MIN_MINBE, + NL802154_CAP_ATTR_MAX_MINBE, + + NL802154_CAP_ATTR_MIN_MAXBE, + NL802154_CAP_ATTR_MAX_MAXBE, + + NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS, + NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS, + + NL802154_CAP_ATTR_MIN_FRAME_RETRIES, + NL802154_CAP_ATTR_MAX_FRAME_RETRIES, + + NL802154_CAP_ATTR_LBT, + + /* keep last */ + __NL802154_CAP_ATTR_AFTER_LAST, + NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl802154_cca_modes - cca modes * * @__NL802154_CCA_INVALID: cca mode number 0 is reserved @@ -162,4 +219,26 @@ enum nl802154_cca_opts { NL802154_CCA_OPT_ATTR_MAX = __NL802154_CCA_OPT_ATTR_AFTER_LAST - 1 }; +/** + * enum nl802154_supported_bool_states - bool states for bool capability entry + * + * @NL802154_SUPPORTED_BOOL_FALSE: indicates to set false + * @NL802154_SUPPORTED_BOOL_TRUE: indicates to set true + * @__NL802154_SUPPORTED_BOOL_INVALD: reserved + * @NL802154_SUPPORTED_BOOL_BOTH: indicates to set true and false + * @__NL802154_SUPPORTED_BOOL_AFTER_LAST: Internal + * @NL802154_SUPPORTED_BOOL_MAX: highest value for bool states + */ +enum nl802154_supported_bool_states { + NL802154_SUPPORTED_BOOL_FALSE, + NL802154_SUPPORTED_BOOL_TRUE, + /* to handle them in a mask */ + __NL802154_SUPPORTED_BOOL_INVALD, + NL802154_SUPPORTED_BOOL_BOTH, + + /* keep last */ + __NL802154_SUPPORTED_BOOL_AFTER_LAST, + NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 +}; + #endif /* __NL802154_H */ diff --git a/src/nl_extras.h b/src/nl_extras.h index a591461..9d841aa 100644 --- a/src/nl_extras.h +++ b/src/nl_extras.h @@ -28,6 +28,11 @@ static inline int8_t nla_get_s8(struct nlattr *nla) #define NLA_PUT_S32(n, attrtype, value) \ NLA_PUT_TYPE(n, int32_t, attrtype, value) +static inline int32_t nla_get_s32(struct nlattr *nla) +{ + return *(int32_t *) nla_data(nla); +} + #endif /* NLA_S32 */ #ifndef NLA_S64 -- 2.3.6 -- To unsubscribe from this list: send the line "unsubscribe linux-wpan" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html