nl802154: add support for dump phy capabilities
authorAlexander Aring <alex.aring@gmail.com>
Sun, 17 May 2015 19:44:53 +0000 (21:44 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 19 May 2015 09:44:44 +0000 (11:44 +0200)
This patch add support to nl802154 to dump all phy capabilities which is
inside the wpan_phy_supported struct. Also we introduce a new method to
dumping supported channels. The new method will offer a easier interface
and has lesser netlink traffic.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/nl802154.h
net/ieee802154/nl802154.c

index 055277156eefc9339aa0abcf32601372df3c60be..0badebd1de7fbe179542a440f31e9042821a2e3d 100644 (file)
@@ -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,
@@ -119,6 +121,61 @@ enum nl802154_iftype {
        NL802154_IFTYPE_MAX = NUM_NL802154_IFTYPES - 1
 };
 
+/**
+ * enum nl802154_wpan_phy_capability_attr - wpan phy 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_wpan_phy_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
  *
index 3afb20e43ff80c6b061789f5f0de8a103c1d7f2e..54f4959fc9bbc7c9d8def7b1426199b9553e4556 100644 (file)
@@ -225,6 +225,8 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
        [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, },
 
        [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, },
+
+       [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED },
 };
 
 /* message building helper */
@@ -235,6 +237,28 @@ static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
        return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
 }
 
+static int
+nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
+{
+       struct nlattr *nl_flags = nla_nest_start(msg, attr);
+       int i;
+
+       if (!nl_flags)
+               return -ENOBUFS;
+
+       i = 0;
+       while (mask) {
+               if ((mask & 1) && nla_put_flag(msg, i))
+                       return -ENOBUFS;
+
+               mask >>= 1;
+               i++;
+       }
+
+       nla_nest_end(msg, nl_flags);
+       return 0;
+}
+
 static int
 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
                                struct sk_buff *msg)
@@ -256,6 +280,92 @@ nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
        return 0;
 }
 
+static int
+nl802154_put_capabilities(struct sk_buff *msg,
+                         struct cfg802154_registered_device *rdev)
+{
+       const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
+       struct nlattr *nl_caps, *nl_channels;
+       int i;
+
+       nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
+       if (!nl_caps)
+               return -ENOBUFS;
+
+       nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
+       if (!nl_channels)
+               return -ENOBUFS;
+
+       for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
+               if (caps->channels[i]) {
+                       if (nl802154_put_flags(msg, i, caps->channels[i]))
+                               return -ENOBUFS;
+               }
+       }
+
+       nla_nest_end(msg, nl_channels);
+
+       if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
+               struct nlattr *nl_ed_lvls;
+
+               nl_ed_lvls = nla_nest_start(msg,
+                                           NL802154_CAP_ATTR_CCA_ED_LEVELS);
+               if (!nl_ed_lvls)
+                       return -ENOBUFS;
+
+               for (i = 0; i < caps->cca_ed_levels_size; i++) {
+                       if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
+                               return -ENOBUFS;
+               }
+
+               nla_nest_end(msg, nl_ed_lvls);
+       }
+
+       if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
+               struct nlattr *nl_tx_pwrs;
+
+               nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
+               if (!nl_tx_pwrs)
+                       return -ENOBUFS;
+
+               for (i = 0; i < caps->tx_powers_size; i++) {
+                       if (nla_put_s32(msg, i, caps->tx_powers[i]))
+                               return -ENOBUFS;
+               }
+
+               nla_nest_end(msg, nl_tx_pwrs);
+       }
+
+       if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
+               if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
+                                      caps->cca_modes) ||
+                   nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
+                                      caps->cca_opts))
+                       return -ENOBUFS;
+       }
+
+       if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
+           nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
+           nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
+           nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
+           nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
+                      caps->min_csma_backoffs) ||
+           nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
+                      caps->max_csma_backoffs) ||
+           nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
+                      caps->min_frame_retries) ||
+           nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
+                      caps->max_frame_retries) ||
+           nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
+                              caps->iftypes) ||
+           nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
+               return -ENOBUFS;
+
+       nla_nest_end(msg, nl_caps);
+
+       return 0;
+}
+
 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
                                  enum nl802154_commands cmd,
                                  struct sk_buff *msg, u32 portid, u32 seq,
@@ -286,7 +396,9 @@ static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
                       rdev->wpan_phy.current_channel))
                goto nla_put_failure;
 
-       /* supported channels array */
+       /* TODO remove this behaviour, we still keep support it for a while
+        * so users can change the behaviour to the new one.
+        */
        if (nl802154_send_wpan_phy_channels(rdev, msg))
                goto nla_put_failure;
 
@@ -309,6 +421,9 @@ static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
                        goto nla_put_failure;
        }
 
+       if (nl802154_put_capabilities(msg, rdev))
+               goto nla_put_failure;
+
 finish:
        genlmsg_end(msg, hdr);
        return 0;