cfg80211: Advertise extended capabilities per interface type to userspace
authorKanchanapally, Vidyullatha <vkanchan@qti.qualcomm.com>
Mon, 16 May 2016 05:11:04 +0000 (10:41 +0530)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 31 May 2016 13:23:13 +0000 (15:23 +0200)
The driver extended capabilities may differ for different
interface types which the userspace needs to know (for
example the fine timing measurement initiator and responder
bits might differ for a station and AP). Add a new nl80211
attribute to provide extended capabilities per interface type
to userspace.

Signed-off-by: Vidyullatha Kanchanapally <vkanchan@qti.qualcomm.com>
Reviewed-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/core.c
net/wireless/nl80211.c

index 537f010cf5e13f388e39903c548beb357033de6d..7bbb00d8b2cdda85b9fff71d89cca69a88c61a6c 100644 (file)
@@ -3083,6 +3083,24 @@ struct wiphy_vendor_command {
                      unsigned long *storage);
 };
 
+/**
+ * struct wiphy_iftype_ext_capab - extended capabilities per interface type
+ * @iftype: interface type
+ * @extended_capabilities: extended capabilities supported by the driver,
+ *     additional capabilities might be supported by userspace; these are the
+ *     802.11 extended capabilities ("Extended Capabilities element") and are
+ *     in the same format as in the information element. See IEEE Std
+ *     802.11-2012 8.4.2.29 for the defined fields.
+ * @extended_capabilities_mask: mask of the valid values
+ * @extended_capabilities_len: length of the extended capabilities
+ */
+struct wiphy_iftype_ext_capab {
+       enum nl80211_iftype iftype;
+       const u8 *extended_capabilities;
+       const u8 *extended_capabilities_mask;
+       u8 extended_capabilities_len;
+};
+
 /**
  * struct wiphy - wireless hardware description
  * @reg_notifier: the driver's regulatory notification callback,
@@ -3203,9 +3221,14 @@ struct wiphy_vendor_command {
  *     additional capabilities might be supported by userspace; these are
  *     the 802.11 extended capabilities ("Extended Capabilities element")
  *     and are in the same format as in the information element. See
- *     802.11-2012 8.4.2.29 for the defined fields.
+ *     802.11-2012 8.4.2.29 for the defined fields. These are the default
+ *     extended capabilities to be used if the capabilities are not specified
+ *     for a specific interface type in iftype_ext_capab.
  * @extended_capabilities_mask: mask of the valid values
  * @extended_capabilities_len: length of the extended capabilities
+ * @iftype_ext_capab: array of extended capabilities per interface type
+ * @num_iftype_ext_capab: number of interface types for which extended
+ *     capabilities are specified separately.
  * @coalesce: packet coalescing support information
  *
  * @vendor_commands: array of vendor commands supported by the hardware
@@ -3305,6 +3328,9 @@ struct wiphy {
        const u8 *extended_capabilities, *extended_capabilities_mask;
        u8 extended_capabilities_len;
 
+       const struct wiphy_iftype_ext_capab *iftype_ext_capab;
+       unsigned int num_iftype_ext_capab;
+
        /* If multiple wiphys are registered and you're handed e.g.
         * a regular netdev with assigned ieee80211_ptr, you won't
         * know whether it points to a wiphy your driver has registered
index 8d995316aadb76cb8487ab32d106173c02215d75..53c8278827a0dc09e6e2c6517bb6d6c409455112 100644 (file)
@@ -1824,6 +1824,11 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_PAD: attribute used for padding for 64-bit alignment
  *
+ * @NL80211_ATTR_IFTYPE_EXT_CAPA: Nested attribute of the following attributes:
+ *     %NL80211_ATTR_IFTYPE, %NL80211_ATTR_EXT_CAPA,
+ *     %NL80211_ATTR_EXT_CAPA_MASK, to specify the extended capabilities per
+ *     interface type.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2206,6 +2211,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_PAD,
 
+       NL80211_ATTR_IFTYPE_EXT_CAPA,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
index d25c82bc1bbe8e80ee0761b466e16088040c717d..b8e10a9521110be7686542d8341c4f663e64b8d5 100644 (file)
@@ -750,6 +750,36 @@ int wiphy_register(struct wiphy *wiphy)
                nl80211_send_reg_change_event(&request);
        }
 
+       /* Check that nobody globally advertises any capabilities they do not
+        * advertise on all possible interface types.
+        */
+       if (wiphy->extended_capabilities_len &&
+           wiphy->num_iftype_ext_capab &&
+           wiphy->iftype_ext_capab) {
+               u8 supported_on_all, j;
+               const struct wiphy_iftype_ext_capab *capab;
+
+               capab = wiphy->iftype_ext_capab;
+               for (j = 0; j < wiphy->extended_capabilities_len; j++) {
+                       if (capab[0].extended_capabilities_len > j)
+                               supported_on_all =
+                                       capab[0].extended_capabilities[j];
+                       else
+                               supported_on_all = 0x00;
+                       for (i = 1; i < wiphy->num_iftype_ext_capab; i++) {
+                               if (j >= capab[i].extended_capabilities_len) {
+                                       supported_on_all = 0x00;
+                                       break;
+                               }
+                               supported_on_all &=
+                                       capab[i].extended_capabilities[j];
+                       }
+                       if (WARN_ON(wiphy->extended_capabilities[j] &
+                                   ~supported_on_all))
+                               break;
+               }
+       }
+
        rdev->wiphy.registered = true;
        rtnl_unlock();
 
index 03ac2ba8b174a79b13f6bf0e743214cc820900d9..d12044996a0ef9fb20ba9a4ff390e005f9a2275c 100644 (file)
@@ -1264,7 +1264,7 @@ nl80211_send_mgmt_stypes(struct sk_buff *msg,
 struct nl80211_dump_wiphy_state {
        s64 filter_wiphy;
        long start;
-       long split_start, band_start, chan_start;
+       long split_start, band_start, chan_start, capa_start;
        bool split;
 };
 
@@ -1761,6 +1761,47 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                        nla_nest_end(msg, nested);
                }
 
+               state->split_start++;
+               break;
+       case 13:
+               if (rdev->wiphy.num_iftype_ext_capab &&
+                   rdev->wiphy.iftype_ext_capab) {
+                       struct nlattr *nested_ext_capab, *nested;
+
+                       nested = nla_nest_start(msg,
+                                               NL80211_ATTR_IFTYPE_EXT_CAPA);
+                       if (!nested)
+                               goto nla_put_failure;
+
+                       for (i = state->capa_start;
+                            i < rdev->wiphy.num_iftype_ext_capab; i++) {
+                               const struct wiphy_iftype_ext_capab *capab;
+
+                               capab = &rdev->wiphy.iftype_ext_capab[i];
+
+                               nested_ext_capab = nla_nest_start(msg, i);
+                               if (!nested_ext_capab ||
+                                   nla_put_u32(msg, NL80211_ATTR_IFTYPE,
+                                               capab->iftype) ||
+                                   nla_put(msg, NL80211_ATTR_EXT_CAPA,
+                                           capab->extended_capabilities_len,
+                                           capab->extended_capabilities) ||
+                                   nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
+                                           capab->extended_capabilities_len,
+                                           capab->extended_capabilities_mask))
+                                       goto nla_put_failure;
+
+                               nla_nest_end(msg, nested_ext_capab);
+                               if (state->split)
+                                       break;
+                       }
+                       nla_nest_end(msg, nested);
+                       if (i < rdev->wiphy.num_iftype_ext_capab) {
+                               state->capa_start = i + 1;
+                               break;
+                       }
+               }
+
                /* done */
                state->split_start = 0;
                break;