cfg80211: provide a function to report a match for NAN
authorAyala Beker <ayala.beker@intel.com>
Tue, 20 Sep 2016 14:31:17 +0000 (17:31 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 30 Sep 2016 11:21:32 +0000 (13:21 +0200)
Provide a function the driver can call to report a match.
This will send the event to the user space.
If the NAN instance is tied to the owner, the notifications will be
sent to the socket that started the NAN interface only.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
include/uapi/linux/nl80211.h
net/wireless/nl80211.c

index 8574a57e19baed34e75576d1a30d6fa1d84cd18b..5481664b5389102e8d3b8a42561518436e9d2f68 100644 (file)
@@ -5694,6 +5694,43 @@ wiphy_ext_feature_isset(struct wiphy *wiphy,
  */
 void cfg80211_free_nan_func(struct cfg80211_nan_func *f);
 
+/**
+ * struct cfg80211_nan_match_params - NAN match parameters
+ * @type: the type of the function that triggered a match. If it is
+ *      %NL80211_NAN_FUNC_SUBSCRIBE it means that we replied to a subscriber.
+ *      If it is %NL80211_NAN_FUNC_PUBLISH, it means that we got a discovery
+ *      result.
+ *      If it is %NL80211_NAN_FUNC_FOLLOW_UP, we received a follow up.
+ * @inst_id: the local instance id
+ * @peer_inst_id: the instance id of the peer's function
+ * @addr: the MAC address of the peer
+ * @info_len: the length of the &info
+ * @info: the Service Specific Info from the peer (if any)
+ * @cookie: unique identifier of the corresponding function
+ */
+struct cfg80211_nan_match_params {
+       enum nl80211_nan_function_type type;
+       u8 inst_id;
+       u8 peer_inst_id;
+       const u8 *addr;
+       u8 info_len;
+       const u8 *info;
+       u64 cookie;
+};
+
+/**
+ * cfg80211_nan_match - report a match for a NAN function.
+ * @wdev: the wireless device reporting the match
+ * @match: match notification parameters
+ * @gfp: allocation flags
+ *
+ * This function reports that the a NAN function had a match. This
+ * can be a subscribe that had a match or a solicited publish that
+ * was sent. It can also be a follow up that was received.
+ */
+void cfg80211_nan_match(struct wireless_dev *wdev,
+                       struct cfg80211_nan_match_params *match, gfp_t gfp);
+
 /* ethtool helper */
 void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
 
index 9c9c0c352873d4c28253c7d02c7174747ff5d076..995bf802d6041cf9fdd87342cdc5c8cdcf98272c 100644 (file)
@@ -48,6 +48,7 @@
 #define NL80211_MULTICAST_GROUP_REG            "regulatory"
 #define NL80211_MULTICAST_GROUP_MLME           "mlme"
 #define NL80211_MULTICAST_GROUP_VENDOR         "vendor"
+#define NL80211_MULTICAST_GROUP_NAN            "nan"
 #define NL80211_MULTICAST_GROUP_TESTMODE       "testmode"
 
 /**
  *     must be operational (%NL80211_CMD_START_NAN was executed).
  *     It must contain at least one of the following attributes:
  *     %NL80211_ATTR_NAN_MASTER_PREF, %NL80211_ATTR_NAN_DUAL.
+ * @NL80211_CMD_NAN_FUNC_MATCH: Notification sent when a match is reported.
+ *     This will contain a %NL80211_ATTR_NAN_MATCH nested attribute and
+ *     %NL80211_ATTR_COOKIE.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -1060,6 +1064,7 @@ enum nl80211_commands {
        NL80211_CMD_ADD_NAN_FUNCTION,
        NL80211_CMD_DEL_NAN_FUNCTION,
        NL80211_CMD_CHANGE_NAN_CONFIG,
+       NL80211_CMD_NAN_MATCH,
 
        /* add new commands above here */
 
@@ -1926,6 +1931,8 @@ enum nl80211_commands {
  * @NL80211_ATTR_NAN_FUNC: a function that can be added to NAN. See
  *     &enum nl80211_nan_func_attributes for description of this nested
  *     attribute.
+ * @NL80211_ATTR_NAN_MATCH: used to report a match. This is a nested attribute.
+ *     See &enum nl80211_nan_match_attributes.
  *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2324,6 +2331,7 @@ enum nl80211_attrs {
        NL80211_ATTR_NAN_MASTER_PREF,
        NL80211_ATTR_NAN_DUAL,
        NL80211_ATTR_NAN_FUNC,
+       NL80211_ATTR_NAN_MATCH,
 
        /* add attributes here, update the policy in nl80211.c */
 
@@ -5074,4 +5082,27 @@ enum nl80211_nan_srf_attributes {
        NL80211_NAN_SRF_ATTR_MAX = NUM_NL80211_NAN_SRF_ATTR - 1,
 };
 
+/**
+ * enum nl80211_nan_match_attributes - NAN match attributes
+ * @__NL80211_NAN_MATCH_INVALID: invalid
+ * @NL80211_NAN_MATCH_FUNC_LOCAL: the local function that had the
+ *     match. This is a nested attribute.
+ *     See &enum nl80211_nan_func_attributes.
+ * @NL80211_NAN_MATCH_FUNC_PEER: the peer function
+ *     that caused the match. This is a nested attribute.
+ *     See &enum nl80211_nan_func_attributes.
+ *
+ * @NUM_NL80211_NAN_MATCH_ATTR: internal
+ * @NL80211_NAN_MATCH_ATTR_MAX: highest NAN match attribute
+ */
+enum nl80211_nan_match_attributes {
+       __NL80211_NAN_MATCH_INVALID,
+       NL80211_NAN_MATCH_FUNC_LOCAL,
+       NL80211_NAN_MATCH_FUNC_PEER,
+
+       /* keep last */
+       NUM_NL80211_NAN_MATCH_ATTR,
+       NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
+};
+
 #endif /* __LINUX_NL80211_H */
index c0b5ae4af2d80dd2512965235851c6544e7e38b1..0bbd9ed28318347986248f0cacebb35e41c9db13 100644 (file)
@@ -56,6 +56,7 @@ enum nl80211_multicast_groups {
        NL80211_MCGRP_REGULATORY,
        NL80211_MCGRP_MLME,
        NL80211_MCGRP_VENDOR,
+       NL80211_MCGRP_NAN,
        NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
 };
 
@@ -65,6 +66,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
        [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
        [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
        [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
+       [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
 #ifdef CONFIG_NL80211_TESTMODE
        [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
 #endif
@@ -10953,6 +10955,84 @@ static int nl80211_nan_change_config(struct sk_buff *skb,
        return rdev_nan_change_conf(rdev, wdev, &conf, changed);
 }
 
+void cfg80211_nan_match(struct wireless_dev *wdev,
+                       struct cfg80211_nan_match_params *match, gfp_t gfp)
+{
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+       struct nlattr *match_attr, *local_func_attr, *peer_func_attr;
+       struct sk_buff *msg;
+       void *hdr;
+
+       if (WARN_ON(!match->inst_id || !match->peer_inst_id || !match->addr))
+               return;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NAN_MATCH);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+           (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
+                                        wdev->netdev->ifindex)) ||
+           nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
+                             NL80211_ATTR_PAD))
+               goto nla_put_failure;
+
+       if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, match->cookie,
+                             NL80211_ATTR_PAD) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, match->addr))
+               goto nla_put_failure;
+
+       match_attr = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
+       if (!match_attr)
+               goto nla_put_failure;
+
+       local_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_LOCAL);
+       if (!local_func_attr)
+               goto nla_put_failure;
+
+       if (nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->inst_id))
+               goto nla_put_failure;
+
+       nla_nest_end(msg, local_func_attr);
+
+       peer_func_attr = nla_nest_start(msg, NL80211_NAN_MATCH_FUNC_PEER);
+       if (!peer_func_attr)
+               goto nla_put_failure;
+
+       if (nla_put_u8(msg, NL80211_NAN_FUNC_TYPE, match->type) ||
+           nla_put_u8(msg, NL80211_NAN_FUNC_INSTANCE_ID, match->peer_inst_id))
+               goto nla_put_failure;
+
+       if (match->info && match->info_len &&
+           nla_put(msg, NL80211_NAN_FUNC_SERVICE_INFO, match->info_len,
+                   match->info))
+               goto nla_put_failure;
+
+       nla_nest_end(msg, peer_func_attr);
+       nla_nest_end(msg, match_attr);
+       genlmsg_end(msg, hdr);
+
+       if (!wdev->owner_nlportid)
+               genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
+                                       msg, 0, NL80211_MCGRP_NAN, gfp);
+       else
+               genlmsg_unicast(wiphy_net(&rdev->wiphy), msg,
+                               wdev->owner_nlportid);
+
+       return;
+
+nla_put_failure:
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_nan_match);
+
 static int nl80211_get_protocol_features(struct sk_buff *skb,
                                         struct genl_info *info)
 {