All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking
@ 2015-03-30 14:14 Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 1/5] cfg80211: add start / stop NAN commands Emmanuel Grumbach
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-03-30 14:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach

This patch series add supports for a new WiFi feature called
Neighbor Awareness Networking a.k.a. NAN.
It is built from the following layers:
 * Time synchronization
 * Discovery Engine (DE)

Time synchronization (MAC Layer):
---------------------------------

NAN allows service discovery within a group of devices: a
cluster. At least one device in the cluster is sending
beacons to keep all the other devices synchronized and to
allow new devices to find and join the cluster. This device
is called "master".
Since sending beacons costs power, the spec allows each
device to set a number which will reflect if it wants to be
master or not. This number is called "master preference" and
can change while NAN is active.

At specific times (16ms every 512ms on each supported band),
a NAN device must stay awake on channel to exchange
information with the other devices in the cluster. This
period of time is called Discovery Window (DW).

Clusters can merge based on rules defined by the spec. The
cluster survivability to disappearing nodes is also ensured
by the spec.

Discovery Engine (DE):
----------------------

The DE can send frames in the DW, this makes sure that all
the devices in the cluster are awake and on channel.
The DE contains NAN functions that can be:
 * publish
 * subscribe
 * follow-up

Each one of these has specific parameters. For example, a
NAN device can actively subscribe to a service. In this case
it will send frames to say it is looking for a service.
A device can also subsribe without sending any frames, this
is called "passive subscribe".
A device can publish a service and send a frame to advertise
the service only if it is requested by an active subscriber.
This is called "solicited publish". A device can also
publish a service and send frames to advertise the service
regardless of the presence or absence of subscribers for
this specific service. This is called "unsolicited publish".
A device can send follow-up frames which allow to get more
info about a specific service.

One of the main goals of NAN is to provide a low power
mechanism for service discovery. Hence, most devices
implementing NAN are expected to offload the layers
described above into the device. This means that cfg80211
/ mac80211 won't do much besides being a pass through for
the configuration. This still means that we need to add a
new vif type and add quite a bit of code to do just that.

Emmanuel Grumbach (5):
  cfg80211: add start / stop NAN commands
  mac80211: add boilerplate code for start / stop NAN
  cfg80211: add add_nan_func / rm_nan_func
  cfg80211: allow the user space to change the NAN master preference
  cfg80211: provide a function to report a match for NAN

 include/net/cfg80211.h       | 108 +++++++++-
 include/net/mac80211.h       |   6 +
 include/uapi/linux/nl80211.h | 198 +++++++++++++++++
 net/mac80211/cfg.c           |  38 ++++
 net/mac80211/chan.c          |   6 +
 net/mac80211/driver-ops.h    |  29 ++-
 net/mac80211/iface.c         |  12 +-
 net/mac80211/main.c          |   4 +
 net/mac80211/offchannel.c    |   3 +-
 net/mac80211/trace.h         |  48 +++++
 net/mac80211/util.c          |   4 +-
 net/wireless/chan.c          |   2 +
 net/wireless/core.c          |  35 +++
 net/wireless/core.h          |   3 +
 net/wireless/mlme.c          |   1 +
 net/wireless/nl80211.c       | 497 ++++++++++++++++++++++++++++++++++++++++++-
 net/wireless/rdev-ops.h      |  57 +++++
 net/wireless/trace.h         |  77 +++++++
 net/wireless/util.c          |   9 +-
 19 files changed, 1126 insertions(+), 11 deletions(-)

-- 
1.9.1


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [RFC 1/5] cfg80211: add start / stop NAN commands
  2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
@ 2015-03-30 14:14 ` Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 2/5] mac80211: add boilerplate code for start / stop NAN Emmanuel Grumbach
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-03-30 14:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach

This allows user space to add / remove a NAN interface.
A NAN interface is like P2P device in a few aspects: it
doesn't have a netdev associated to it.
Add the new interface type and prevent operations that
can't be executed on NAN interface like scan.
The only parameter we need to start a cluster is the master
preference. The higher it is, the more likely it is that
the device will be master in its cluster.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
 include/net/cfg80211.h       |  9 ++++-
 include/uapi/linux/nl80211.h | 19 ++++++++++
 net/mac80211/cfg.c           |  3 ++
 net/mac80211/chan.c          |  3 ++
 net/mac80211/iface.c         |  4 ++
 net/mac80211/util.c          |  1 +
 net/wireless/chan.c          |  2 +
 net/wireless/core.c          | 34 +++++++++++++++++
 net/wireless/core.h          |  3 ++
 net/wireless/mlme.c          |  1 +
 net/wireless/nl80211.c       | 87 ++++++++++++++++++++++++++++++++++++++++++--
 net/wireless/rdev-ops.h      | 19 ++++++++++
 net/wireless/trace.h         | 23 ++++++++++++
 net/wireless/util.c          |  9 ++++-
 14 files changed, 211 insertions(+), 6 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index cb20bbb..5e9a45d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2365,6 +2365,9 @@ struct cfg80211_qos_map {
  * @start_p2p_device: Start the given P2P device.
  * @stop_p2p_device: Stop the given P2P device.
  *
+ * @start_nan: Start the NAN interface.
+ * @stop_nan: Stop the NAN interface.
+ *
  * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
  *	Parameters include ACL policy, an array of MAC address of stations
  *	and the number of MAC addresses. If there is already a list in driver
@@ -2682,6 +2685,9 @@ struct cfg80211_ops {
 	void	(*tdls_cancel_channel_switch)(struct wiphy *wiphy,
 					      struct net_device *dev,
 					      const u8 *addr);
+	int	(*start_nan)(struct wiphy *wiphy, struct wireless_dev *wdev,
+			     u8 master_pref);
+	void	(*stop_nan)(struct wiphy *wiphy, struct wireless_dev *wdev);
 };
 
 /*
@@ -3390,6 +3396,7 @@ struct cfg80211_cached_keys;
  *	beacons, 0 when not valid
  * @address: The address for this device, valid only if @netdev is %NULL
  * @p2p_started: true if this is a P2P Device that has been started
+ * @nan_started: true if this is a NAN interface that has been started
  * @cac_started: true if DFS channel availability check has been started
  * @cac_start_time: timestamp (jiffies) when the dfs state was entered.
  * @cac_time_ms: CAC time in ms
@@ -3420,7 +3427,7 @@ struct wireless_dev {
 
 	struct mutex mtx;
 
-	bool use_4addr, p2p_started;
+	bool use_4addr, p2p_started, nan_started;
 
 	u8 address[ETH_ALEN] __aligned(sizeof(u16));
 
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9c64d81..b9e1758 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -798,6 +798,15 @@
  *	as an event to indicate changes for devices with wiphy-specific regdom
  *	management.
  *
+ * @NL80211_CMD_START_NAN: Start NAN operation, identified by its
+ *	%NL80211_ATTR_WDEV identifier. It must have been created with
+ *	%NL80211_CMD_NEW_INTERFACE previously. After it has been started, the
+ *	NAN interface will create or join a cluster. This command must have a
+ *	non-zero %NL80211_ATTR_NAN_MASTER_PREF attribute. After this command,
+ *	NAN functions can be added.
+ * @NL80211_CMD_STOP_NAN: Stop the NAN operation, identified by
+ *	its %NL80211_ATTR_WDEV identifier.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -984,6 +993,9 @@ enum nl80211_commands {
 
 	NL80211_CMD_WIPHY_REG_CHANGE,
 
+	NL80211_CMD_START_NAN,
+	NL80211_CMD_STOP_NAN,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1742,6 +1754,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
  *	WoWLAN net-detect scan) is started, u32 in seconds.
  *
+ * @NL80211_ATTR_NAN_MASTER_PREF: the master preference to be be used by
+ *	&NL80211_CMD_START_NAN. Its type is u8 and it can't be 0, 1 or 255.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2108,6 +2123,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_NETNS_FD,
 
 	NL80211_ATTR_SCHED_SCAN_DELAY,
+
+	NL80211_ATTR_NAN_MASTER_PREF,
 	
 	NL80211_ATTR_REG_INDOOR,
 
@@ -2189,6 +2206,7 @@ enum nl80211_attrs {
  *	commands to create and destroy one
  * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
  *	This mode corresponds to the MIB variable dot11OCBActivated=true
+ * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev)
  * @NL80211_IFTYPE_MAX: highest interface type number currently defined
  * @NUM_NL80211_IFTYPES: number of defined interface types
  *
@@ -2209,6 +2227,7 @@ enum nl80211_iftype {
 	NL80211_IFTYPE_P2P_GO,
 	NL80211_IFTYPE_P2P_DEVICE,
 	NL80211_IFTYPE_OCB,
+	NL80211_IFTYPE_NAN,
 
 	/* keep last */
 	NUM_NL80211_IFTYPES,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5e24419..b37092f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -231,6 +231,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 	case NL80211_IFTYPE_WDS:
 	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_P2P_DEVICE:
+	case NL80211_IFTYPE_NAN:
 	case NL80211_IFTYPE_UNSPECIFIED:
 	case NUM_NL80211_IFTYPES:
 	case NL80211_IFTYPE_P2P_CLIENT:
@@ -2003,6 +2004,7 @@ static int ieee80211_scan(struct wiphy *wiphy,
 		     !(req->flags & NL80211_SCAN_FLAG_AP)))
 			return -EOPNOTSUPP;
 		break;
+	case NL80211_IFTYPE_NAN:
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -3378,6 +3380,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 	case NL80211_IFTYPE_P2P_DEVICE:
 		need_offchan = true;
 		break;
+	case NL80211_IFTYPE_NAN:
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 35b11e1..794ccc6 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -265,6 +265,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
 			width = ieee80211_get_max_required_bw(sdata);
 			break;
 		case NL80211_IFTYPE_P2P_DEVICE:
+		case NL80211_IFTYPE_NAN:
 			continue;
 		case NL80211_IFTYPE_STATION:
 		case NL80211_IFTYPE_ADHOC:
@@ -691,6 +692,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 
 		switch (sdata->vif.type) {
 		case NL80211_IFTYPE_P2P_DEVICE:
+		case NL80211_IFTYPE_NAN:
 			continue;
 		case NL80211_IFTYPE_STATION:
 			if (!sdata->u.mgd.associated)
@@ -954,6 +956,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
 	case NL80211_IFTYPE_P2P_GO:
 	case NL80211_IFTYPE_P2P_DEVICE:
 	case NUM_NL80211_IFTYPES:
+	case NL80211_IFTYPE_NAN:
 		WARN_ON(1);
 		break;
 	}
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 05b7920..e033af0 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -533,6 +533,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 	case NL80211_IFTYPE_ADHOC:
 	case NL80211_IFTYPE_P2P_DEVICE:
 	case NL80211_IFTYPE_OCB:
+	case NL80211_IFTYPE_NAN:
 		/* no special treatment */
 		break;
 	case NL80211_IFTYPE_UNSPECIFIED:
@@ -648,6 +649,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 			break;
 		case NL80211_IFTYPE_WDS:
 		case NL80211_IFTYPE_P2P_DEVICE:
+		case NL80211_IFTYPE_NAN:
 			break;
 		default:
 			/* not reached */
@@ -937,6 +939,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 		/* relies on synchronize_rcu() below */
 		RCU_INIT_POINTER(local->p2p_sdata, NULL);
 		/* fall through */
+	case NL80211_IFTYPE_NAN:
 	default:
 		cancel_work_sync(&sdata->work);
 		/*
@@ -1416,6 +1419,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 		break;
 	case NL80211_IFTYPE_AP_VLAN:
 	case NL80211_IFTYPE_P2P_DEVICE:
+	case NL80211_IFTYPE_NAN:
 		sdata->vif.bss_conf.bssid = sdata->vif.addr;
 		break;
 	case NL80211_IFTYPE_UNSPECIFIED:
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3278867..11d515f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1953,6 +1953,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 		case NL80211_IFTYPE_AP_VLAN:
 		case NL80211_IFTYPE_MONITOR:
 		case NL80211_IFTYPE_P2P_DEVICE:
+		case NL80211_IFTYPE_NAN:
 			/* nothing to do */
 			break;
 		case NL80211_IFTYPE_UNSPECIFIED:
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index a74ce38..87db715 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -372,6 +372,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 	case NL80211_IFTYPE_AP_VLAN:
 	case NL80211_IFTYPE_WDS:
 	case NL80211_IFTYPE_P2P_DEVICE:
+	case NL80211_IFTYPE_NAN:
 		break;
 	case NL80211_IFTYPE_UNSPECIFIED:
 	case NUM_NL80211_IFTYPES:
@@ -922,6 +923,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
 	case NL80211_IFTYPE_AP_VLAN:
 	case NL80211_IFTYPE_WDS:
 	case NL80211_IFTYPE_P2P_DEVICE:
+	case NL80211_IFTYPE_NAN:
 		/* these interface types don't really have a channel */
 		return;
 	case NL80211_IFTYPE_UNSPECIFIED:
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 2e7ddb1..1a1fae0 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -229,6 +229,23 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
 	}
 }
 
+void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
+		       struct wireless_dev *wdev)
+{
+	ASSERT_RTNL();
+
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
+		return;
+
+	if (!wdev->nan_started)
+		return;
+
+	rdev_stop_nan(rdev, wdev);
+	wdev->nan_started = false;
+
+	rdev->opencount--;
+}
+
 void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -246,6 +263,9 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
 		case NL80211_IFTYPE_P2P_DEVICE:
 			cfg80211_stop_p2p_device(rdev, wdev);
 			break;
+		case NL80211_IFTYPE_NAN:
+			cfg80211_stop_nan(rdev, wdev);
+			break;
 		default:
 			break;
 		}
@@ -532,6 +552,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
 				    c->limits[j].max > 1))
 				return -EINVAL;
 
+			/* Only a single NAN can be allowed */
+			if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
+				    c->limits[j].max > 1))
+				return -EINVAL;
+
 			cnt += c->limits[j].max;
 			/*
 			 * Don't advertise an unsupported type
@@ -574,6 +599,10 @@ int wiphy_register(struct wiphy *wiphy)
 		     !rdev->ops->tdls_cancel_channel_switch)))
 		return -EINVAL;
 
+	if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN)) &&
+		    (!rdev->ops->start_nan || !rdev->ops->stop_nan)))
+		return -EINVAL;
+
 	/*
 	 * if a wiphy has unsupported modes for regulatory channel enforcement,
 	 * opt-out of enforcement checking
@@ -584,6 +613,7 @@ int wiphy_register(struct wiphy *wiphy)
 				       BIT(NL80211_IFTYPE_P2P_GO) |
 				       BIT(NL80211_IFTYPE_ADHOC) |
 				       BIT(NL80211_IFTYPE_P2P_DEVICE) |
+				       BIT(NL80211_IFTYPE_NAN) |
 				       BIT(NL80211_IFTYPE_AP_VLAN) |
 				       BIT(NL80211_IFTYPE_MONITOR)))
 		wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
@@ -873,6 +903,9 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 		cfg80211_android_destroy_p2p_device(wdev);
 #endif
 		break;
+	case NL80211_IFTYPE_NAN:
+		cfg80211_stop_nan(rdev, wdev);
+		break;
 	default:
 		WARN_ON_ONCE(1);
 		break;
@@ -936,6 +969,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
 		/* must be handled by mac80211/driver, has no APIs */
 		break;
 	case NL80211_IFTYPE_P2P_DEVICE:
+	case NL80211_IFTYPE_NAN:
 		/* cannot happen, has no netdev */
 		break;
 	case NL80211_IFTYPE_AP_VLAN:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index d6d6530..0d64fa6 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -476,6 +476,9 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
 void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
 			      struct wireless_dev *wdev);
 
+void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
+		       struct wireless_dev *wdev);
+
 #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
 
 #ifdef CPTCFG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 9b18d93..3f8068d 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -587,6 +587,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
 			 * fall through, P2P device only supports
 			 * public action frames
 			 */
+		case NL80211_IFTYPE_NAN:
 		default:
 			err = -EOPNOTSUPP;
 			break;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8d04d3e..6992694 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -407,6 +407,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 	[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
 	[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
 	[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
+	[NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
 };
 
 /* policy for the key attributes */
@@ -900,6 +901,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
 	case NL80211_IFTYPE_UNSPECIFIED:
 	case NL80211_IFTYPE_OCB:
 	case NL80211_IFTYPE_MONITOR:
+	case NL80211_IFTYPE_NAN:
 	case NL80211_IFTYPE_P2P_DEVICE:
 	case NL80211_IFTYPE_WDS:
 	case NUM_NL80211_IFTYPES:
@@ -2654,7 +2656,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 	    !(rdev->wiphy.interface_modes & (1 << type)))
 		return -EOPNOTSUPP;
 
-	if ((type == NL80211_IFTYPE_P2P_DEVICE ||
+	if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
 	     rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
 	    info->attrs[NL80211_ATTR_MAC]) {
 		nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
@@ -2709,9 +2711,10 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 		       wdev->mesh_id_up_len);
 		wdev_unlock(wdev);
 		break;
+	case NL80211_IFTYPE_NAN:
 	case NL80211_IFTYPE_P2P_DEVICE:
 		/*
-		 * P2P Device doesn't have a netdev, so doesn't go
+		 * P2P Device and NAN do not have a netdev, so don't go
 		 * through the netdev notifier and must be added here
 		 */
 		mutex_init(&wdev->mtx);
@@ -2725,6 +2728,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 		rdev->devlist_generation++;
 
 #ifdef CPTCFG_CFG80211_ANDROID_P2P_HACK
+		if (type == NL80211_IFTYPE_NAN)
+			break;
+
 		err = cfg80211_android_create_p2p_device(wdev,
 				nla_data(info->attrs[NL80211_ATTR_IFNAME]));
 		if (err) {
@@ -5759,6 +5765,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 
 	wiphy = &rdev->wiphy;
 
+	if (wdev->iftype == NL80211_IFTYPE_NAN)
+		return -EOPNOTSUPP;
+
 	if (!rdev->ops->scan)
 		return -EOPNOTSUPP;
 
@@ -8289,6 +8298,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
 	case NL80211_IFTYPE_P2P_GO:
 	case NL80211_IFTYPE_P2P_DEVICE:
 		break;
+	case NL80211_IFTYPE_NAN:
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -8335,6 +8345,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 	case NL80211_IFTYPE_MESH_POINT:
 	case NL80211_IFTYPE_P2P_GO:
 		break;
+	case NL80211_IFTYPE_NAN:
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -8452,6 +8463,7 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in
 	case NL80211_IFTYPE_P2P_GO:
 	case NL80211_IFTYPE_P2P_DEVICE:
 		break;
+	case NL80211_IFTYPE_NAN:
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -9783,6 +9795,52 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
+static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct wireless_dev *wdev = info->user_ptr[1];
+	u8 master_pref;
+	int err;
+
+	if (wdev->iftype != NL80211_IFTYPE_NAN)
+		return -EOPNOTSUPP;
+
+	if (wdev->nan_started)
+		return -EEXIST;
+
+	if (rfkill_blocked(rdev->rfkill))
+		return -ERFKILL;
+
+	if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
+		return -EINVAL;
+
+	master_pref = nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
+	if (master_pref <= 1 || master_pref == 255)
+		return -EINVAL;
+
+	err = rdev_start_nan(rdev, wdev, master_pref);
+	if (err)
+		return err;
+
+	wdev->nan_started = true;
+	rdev->opencount++;
+
+	return 0;
+}
+
+static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct wireless_dev *wdev = info->user_ptr[1];
+
+	if (wdev->iftype != NL80211_IFTYPE_NAN)
+		return -EOPNOTSUPP;
+
+	cfg80211_stop_nan(rdev, wdev);
+
+	return 0;
+}
+
 static int nl80211_get_protocol_features(struct sk_buff *skb,
 					 struct genl_info *info)
 {
@@ -10300,7 +10358,14 @@ static int nl80211_pre_doit(__genl_const struct genl_ops *ops, struct sk_buff *s
 
 			dev_hold(dev);
 		} else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
-			if (!wdev->p2p_started) {
+			if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
+			    !wdev->p2p_started) {
+				if (rtnl)
+					rtnl_unlock();
+				return -ENETDOWN;
+			}
+			if (wdev->iftype == NL80211_IFTYPE_NAN &&
+			    !wdev->nan_started) {
 				if (rtnl)
 					rtnl_unlock();
 				return -ENETDOWN;
@@ -10924,6 +10989,22 @@ static __genl_const struct genl_ops nl80211_ops[] = {
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
+		.cmd = NL80211_CMD_START_NAN,
+		.doit = nl80211_start_nan,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_WDEV |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_STOP_NAN,
+		.doit = nl80211_stop_nan,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
 		.cmd = NL80211_CMD_SET_MCAST_RATE,
 		.doit = nl80211_set_mcast_rate,
 		.policy = nl80211_policy,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 0336264..593fbb7 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -876,6 +876,25 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev,
 	trace_rdev_return_void(&rdev->wiphy);
 }
 
+static inline int rdev_start_nan(struct cfg80211_registered_device *rdev,
+				 struct wireless_dev *wdev, u8 master_pref)
+{
+	int ret;
+
+	trace_rdev_start_nan(&rdev->wiphy, wdev, master_pref);
+	ret = rdev->ops->start_nan(&rdev->wiphy, wdev, master_pref);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
+static inline void rdev_stop_nan(struct cfg80211_registered_device *rdev,
+				 struct wireless_dev *wdev)
+{
+	trace_rdev_stop_nan(&rdev->wiphy, wdev);
+	rdev->ops->stop_nan(&rdev->wiphy, wdev);
+	trace_rdev_return_void(&rdev->wiphy);
+}
+
 static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
 				   struct net_device *dev,
 				   struct cfg80211_acl_data *params)
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 4dedf11..3718563 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1854,6 +1854,29 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_p2p_device,
 	TP_ARGS(wiphy, wdev)
 );
 
+TRACE_EVENT(rdev_start_nan,
+	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+		 u8 master_pref),
+	TP_ARGS(wiphy, wdev, master_pref),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		WDEV_ENTRY
+		__field(u8, master_pref)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		WDEV_ASSIGN;
+		__entry->master_pref = master_pref;
+	),
+	TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", master preference: %u",
+		  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->master_pref)
+);
+
+DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_nan,
+	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+	TP_ARGS(wiphy, wdev)
+);
+
 TRACE_EVENT(rdev_set_mac_acl,
 	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
 		 struct cfg80211_acl_data *params),
diff --git a/net/wireless/util.c b/net/wireless/util.c
index b25aa65..3990c8b 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -929,8 +929,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 	if (otype == NL80211_IFTYPE_AP_VLAN)
 		return -EOPNOTSUPP;
 
-	/* cannot change into P2P device type */
-	if (ntype == NL80211_IFTYPE_P2P_DEVICE)
+	/* cannot change into P2P device or nan */
+	if (ntype == NL80211_IFTYPE_P2P_DEVICE ||
+	    ntype == NL80211_IFTYPE_NAN)
 		return -EOPNOTSUPP;
 
 	if (!rdev->ops->change_virtual_intf ||
@@ -1009,6 +1010,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 			/* not happening */
 			break;
 		case NL80211_IFTYPE_P2P_DEVICE:
+		case NL80211_IFTYPE_NAN:
 			WARN_ON(1);
 			break;
 		}
@@ -1510,6 +1512,9 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
 		if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) {
 			if (!wdev_iter->p2p_started)
 				continue;
+		} else if (wdev_iter->iftype == NL80211_IFTYPE_NAN) {
+			if (!wdev_iter->nan_started)
+				continue;
 		} else if (wdev_iter->netdev) {
 			if (!netif_running(wdev_iter->netdev))
 				continue;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC 2/5] mac80211: add boilerplate code for start / stop NAN
  2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 1/5] cfg80211: add start / stop NAN commands Emmanuel Grumbach
@ 2015-03-30 14:14 ` Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 3/5] cfg80211: add add_nan_func / rm_nan_func Emmanuel Grumbach
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-03-30 14:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach

This codes doens't do much besides allowing to start and
stop the vif.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
 include/net/mac80211.h    |  6 ++++++
 net/mac80211/cfg.c        | 35 ++++++++++++++++++++++++++++++++++
 net/mac80211/chan.c       |  3 +++
 net/mac80211/driver-ops.h | 29 +++++++++++++++++++++++++++-
 net/mac80211/iface.c      |  8 ++++++--
 net/mac80211/main.c       |  4 ++++
 net/mac80211/offchannel.c |  3 ++-
 net/mac80211/trace.h      | 48 +++++++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/util.c       |  3 ++-
 9 files changed, 134 insertions(+), 5 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cfbee18..8cd030f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3053,6 +3053,8 @@ enum ieee80211_reconfig_type {
  *	response template is provided, together with the location of the
  *	switch-timing IE within the template. The skb can only be used within
  *	the function call.
+ * @start_nan: join an existing nan cluster, or create a new one.
+ * @stop_nan: leave the nan cluster.
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw,
@@ -3285,6 +3287,10 @@ struct ieee80211_ops {
 	void (*tdls_recv_channel_switch)(struct ieee80211_hw *hw,
 					 struct ieee80211_vif *vif,
 					 struct ieee80211_tdls_ch_sw_params *params);
+	int (*start_nan)(struct ieee80211_hw *hw,
+			 struct ieee80211_vif *vif, u8 master_pref);
+	int (*stop_nan)(struct ieee80211_hw *hw,
+			struct ieee80211_vif *vif);
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index b37092f..c95488d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -129,6 +129,39 @@ static void ieee80211_stop_p2p_device(struct wiphy *wiphy,
 	ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev));
 }
 
+static int ieee80211_start_nan(struct wiphy *wiphy,
+			       struct wireless_dev *wdev,
+			       u8 master_pref)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+	int ret;
+
+	mutex_lock(&sdata->local->chanctx_mtx);
+	ret = ieee80211_check_combinations(sdata, NULL, 0, 0);
+	mutex_unlock(&sdata->local->chanctx_mtx);
+	if (ret < 0)
+		return ret;
+
+	ret = ieee80211_do_open(wdev, true);
+	if (ret)
+		return ret;
+
+	ret = drv_start_nan(sdata->local, sdata, master_pref);
+	if (ret)
+		ieee80211_sdata_stop(sdata);
+
+	return ret;
+}
+
+static void ieee80211_stop_nan(struct wiphy *wiphy,
+			       struct wireless_dev *wdev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+	drv_stop_nan(sdata->local, sdata);
+	ieee80211_sdata_stop(sdata);
+}
+
 static int ieee80211_set_noack_map(struct wiphy *wiphy,
 				  struct net_device *dev,
 				  u16 noack_map)
@@ -3854,4 +3887,6 @@ const struct cfg80211_ops mac80211_config_ops = {
 	.set_ap_chanwidth = ieee80211_set_ap_chanwidth,
 	.add_tx_ts = ieee80211_add_tx_ts,
 	.del_tx_ts = ieee80211_del_tx_ts,
+	.start_nan = ieee80211_start_nan,
+	.stop_nan = ieee80211_stop_nan,
 };
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 794ccc6..29da2d5 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -622,6 +622,9 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_chanctx *curr_ctx = NULL;
 	int ret = 0;
 
+	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_NAN))
+		return 0;
+
 	conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
 					 lockdep_is_held(&local->chanctx_mtx));
 
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index ab720f2..d58458f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -219,7 +219,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 		return;
 
 	if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
-			 sdata->vif.type == NL80211_IFTYPE_MONITOR))
+			 sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+			 sdata->vif.type == NL80211_IFTYPE_NAN))
 		return;
 
 	if (!check_sdata_in_driver(sdata))
@@ -1366,4 +1367,30 @@ drv_tdls_recv_channel_switch(struct ieee80211_local *local,
 	trace_drv_return_void(local);
 }
 
+static inline int drv_start_nan(struct ieee80211_local *local,
+				struct ieee80211_sub_if_data *sdata,
+				u8 master_pref)
+{
+	int ret;
+
+	might_sleep();
+	check_sdata_in_driver(sdata);
+
+	trace_drv_start_nan(local, sdata, master_pref);
+	ret = local->ops->start_nan(&local->hw, &sdata->vif, master_pref);
+	trace_drv_return_int(local, ret);
+	return ret;
+}
+
+static inline void drv_stop_nan(struct ieee80211_local *local,
+				struct ieee80211_sub_if_data *sdata)
+{
+	might_sleep();
+	check_sdata_in_driver(sdata);
+
+	trace_drv_stop_nan(local, sdata);
+	local->ops->stop_nan(&local->hw, &sdata->vif);
+	trace_drv_return_void(local);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e033af0..ac7c119 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -324,6 +324,9 @@ static int ieee80211_check_queues(struct ieee80211_sub_if_data *sdata,
 	int n_queues = sdata->local->hw.queues;
 	int i;
 
+	if (iftype == NL80211_IFTYPE_NAN)
+		return 0;
+
 	if (iftype != NL80211_IFTYPE_P2P_DEVICE) {
 		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
 			if (WARN_ON_ONCE(sdata->vif.hw_queue[i] ==
@@ -635,7 +638,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 			local->fif_probe_req++;
 		}
 
-		if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE)
+		if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
+		    sdata->vif.type != NL80211_IFTYPE_NAN)
 			changed |= ieee80211_reset_erp_info(sdata);
 		ieee80211_bss_info_change_notify(sdata, changed);
 
@@ -1683,7 +1687,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
 	ASSERT_RTNL();
 
-	if (type == NL80211_IFTYPE_P2P_DEVICE) {
+	if (type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN) {
 		struct wireless_dev *wdev;
 
 		sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 35c0ad6..1763646 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -821,6 +821,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	     !local->ops->tdls_recv_channel_switch))
 		return -EOPNOTSUPP;
 
+	if (WARN_ON(local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN) &&
+		    (!local->ops->start_nan || !local->ops->stop_nan)))
+		return -EINVAL;
+
 #ifdef CONFIG_PM
 	if (hw->wiphy->wowlan && (!local->ops->suspend || !local->ops->resume))
 		return -EINVAL;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 683f0e3..4f17b1e 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -128,7 +128,8 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
 		if (!ieee80211_sdata_running(sdata))
 			continue;
 
-		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
+		if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
+		    sdata->vif.type == NL80211_IFTYPE_NAN)
 			continue;
 
 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 838bd92..a97ac97 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1656,6 +1656,54 @@ TRACE_EVENT(drv_get_expected_throughput,
 	)
 );
 
+TRACE_EVENT(drv_start_nan,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 u8 master_pref),
+
+	TP_ARGS(local, sdata, master_pref),
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(u8, master_pref)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->master_pref = master_pref;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT
+		", master_pref: %u",
+		LOCAL_PR_ARG, VIF_PR_ARG,
+		__entry->master_pref
+	)
+);
+
+TRACE_EVENT(drv_stop_nan,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata),
+
+	TP_ARGS(local, sdata),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT,
+		LOCAL_PR_ARG, VIF_PR_ARG
+	)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 11d515f..c3726c4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1235,7 +1235,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 	}
 
 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) {
+	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
+	    sdata->vif.type != NL80211_IFTYPE_NAN) {
 		sdata->vif.bss_conf.qos = enable_qos;
 		if (bss_notify)
 			ieee80211_bss_info_change_notify(sdata,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC 3/5] cfg80211: add add_nan_func / rm_nan_func
  2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 1/5] cfg80211: add start / stop NAN commands Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 2/5] mac80211: add boilerplate code for start / stop NAN Emmanuel Grumbach
@ 2015-03-30 14:14 ` Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 4/5] cfg80211: allow the user space to change the NAN master preference Emmanuel Grumbach
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-03-30 14:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach

A NAN function can be either publish, subscribe or follow
up. Make all the necessary verifications and just pass the
request to the driver.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
 include/net/cfg80211.h       |  71 ++++++++++
 include/uapi/linux/nl80211.h | 138 ++++++++++++++++++++
 net/wireless/core.c          |   3 +-
 net/wireless/nl80211.c       | 300 +++++++++++++++++++++++++++++++++++++++++++
 net/wireless/rdev-ops.h      |  22 ++++
 net/wireless/trace.h         |  36 ++++++
 6 files changed, 569 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5e9a45d..64f45a9 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2152,6 +2152,69 @@ struct cfg80211_qos_map {
 };
 
 /**
+ * struct cfg80211_nan_func_filter - a NAN function Rx / Tx filter
+ *
+ * @filter: the content of the filter
+ * @len: the length of the filter
+ */
+struct cfg80211_nan_func_filter {
+	const u8 *filter;
+	u8 len;
+};
+
+/**
+ * struct cfg80211_nan_func - a NAN function
+ *
+ * @type: &enum nl80211_nan_function_type
+ * @service_id: the service ID of the function
+ * @publish_type: &nl80211_nan_publish_type
+ * @discovery_range: if true, the range should be limited. Threshold is
+ *	implementation specific.
+ * @publish_bcast: if true, the solicited publish should transmit BCAST
+ * @subscribe_active: if true, the subscribe is active
+ * @followup_id: the instance ID for follow up
+ * @followup_reqid: the requestor instance ID for follow up
+ * @followup_dest: MAC address of the recipient of the follow up
+ * @ttl: time to live
+ * @serv_spec_info: Service Specific Info
+ * @serv_spec_info_len: Service Specific Info length
+ * @srf_include: if true, SRF is inclusive
+ * @srf_bf: Bloom Filter
+ * @srf_bf_len: Bloom Filter length
+ * @srf_bf_idx: Blook Filter index
+ * @srf_macs: SRF MAC addresses
+ * @srf_num_macs: number of MAC addresses in SRF
+ * @rx_filters: points to an array of &struct cfg80211_nan_func_filter
+ * @tx_filters: points to an array of &struct cfg80211_nan_func_filter
+ * @num_rx_filters: size of &rx_filters.
+ * @num_tx_filters: size of &tx_filters.
+ */
+struct cfg80211_nan_func {
+	enum nl80211_nan_function_type type;
+	u8 service_id[NL80211_NAN_FUNC_SERVICE_ID_LEN];
+	u8 publish_type;
+	bool discovery_range;
+	bool publish_bcast;
+	bool subscribe_active;
+	u8 followup_id;
+	u8 followup_reqid;
+	struct mac_address followup_dest;
+	u32 ttl;
+	const u8 *serv_spec_info;
+	u8 serv_spec_info_len;
+	bool srf_include;
+	const u8 *srf_bf;
+	u8 srf_bf_len;
+	u8 srf_bf_idx;
+	struct mac_address *srf_macs;
+	int srf_num_macs;
+	struct cfg80211_nan_func_filter *rx_filters;
+	struct cfg80211_nan_func_filter *tx_filters;
+	unsigned int num_tx_filters;
+	unsigned int num_rx_filters;
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2367,6 +2430,10 @@ struct cfg80211_qos_map {
  *
  * @start_nan: Start the NAN interface.
  * @stop_nan: Stop the NAN interface.
+ * @add_nan_func: Add a nan function. Returns a stricly positive instance id
+ *	upon success. The data in cfg80211_nan_func must not be referenced
+ *	outside the scope of this call.
+ * @rm_nan_func: Remove a nan function
  *
  * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
  *	Parameters include ACL policy, an array of MAC address of stations
@@ -2688,6 +2755,10 @@ struct cfg80211_ops {
 	int	(*start_nan)(struct wiphy *wiphy, struct wireless_dev *wdev,
 			     u8 master_pref);
 	void	(*stop_nan)(struct wiphy *wiphy, struct wireless_dev *wdev);
+	int	(*add_nan_func)(struct wiphy *wiphy, struct wireless_dev *wdev,
+				const struct cfg80211_nan_func *nan_func);
+	void	(*rm_nan_func)(struct wiphy *wiphy, struct wireless_dev *wdev,
+				   u8 instance_id);
 };
 
 /*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b9e1758..b3bf9aa 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -806,6 +806,12 @@
  *	NAN functions can be added.
  * @NL80211_CMD_STOP_NAN: Stop the NAN operation, identified by
  *	its %NL80211_ATTR_WDEV identifier.
+ * @NL80211_CMD_ADD_NAN_FUNCTION: add a NAN function. The function a
+ *	%NL80211_ATTR_NAN_FUNC attribute. When called, this operation returns
+ *	the strictly positive instance id (%NL80211_ATTR_NAN_FUNC_INST_ID) of
+ *	the function upon success.
+ * @NL80211_CMD_RM_NAN_FUNCTION: remove a NAN function based on its instance
+ *	id.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -995,6 +1001,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_START_NAN,
 	NL80211_CMD_STOP_NAN,
+	NL80211_CMD_ADD_NAN_FUNCTION,
+	NL80211_CMD_RM_NAN_FUNCTION,
 
 	/* add new commands above here */
 
@@ -1756,6 +1764,11 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_NAN_MASTER_PREF: the master preference to be be used by
  *	&NL80211_CMD_START_NAN. Its type is u8 and it can't be 0, 1 or 255.
+ * @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_FUNC_INST_ID: the instance id of a %NL80211_ATTR_NAN_FUNC.
+ *	Its type is u8 and it cannot be 0.
  *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
@@ -2125,6 +2138,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_SCHED_SCAN_DELAY,
 
 	NL80211_ATTR_NAN_MASTER_PREF,
+	NL80211_ATTR_NAN_FUNC,
+	NL80211_ATTR_NAN_FUNC_INST_ID,
 	
 	NL80211_ATTR_REG_INDOOR,
 
@@ -4586,4 +4601,127 @@ enum nl80211_tdls_peer_capability {
 	NL80211_TDLS_PEER_WMM = 1<<2,
 };
 
+/**
+ * enum nl80211_nan_function_type - NAN function type
+ *
+ * Defines the function type of a NAN function
+ *
+ * @NL80211_NAN_FUNC_PUBLISH: function is publish
+ * @NL80211_NAN_FUNC_SUBSCRIBE: function is subscribe
+ * @NL80211_NAN_FUNC_FOLLOW_UP: function is follow-up
+ * @NL80211_NAN_FUNC_MAX_TYPE: must be last
+ */
+enum nl80211_nan_function_type {
+	NL80211_NAN_FUNC_PUBLISH,
+	NL80211_NAN_FUNC_SUBSCRIBE,
+	NL80211_NAN_FUNC_FOLLOW_UP,
+
+	NL80211_NAN_FUNC_MAX_TYPE,
+};
+
+/**
+ * enum nl80211_nan_publish_type - NAN publish tx type
+ *
+ * Defines how to send publish Service Discovery Frames
+ *
+ * @NL80211_NAN_SOLICITED_PUBLISH: publish function is solicited
+ * @NL80211_NAN_UNSOLICITED_PUBLISH: publish function is unsolicited
+ */
+enum nl80211_nan_publish_type {
+	NL80211_NAN_SOLICITED_PUBLISH = 1<<0,
+	NL80211_NAN_UNSOLICITED_PUBLISH = 1<<1,
+};
+
+#define NL80211_NAN_FUNC_SERVICE_ID_LEN 6
+#define NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN 0xff
+#define NL80211_NAN_FUNC_SRF_MAX_LEN 0xff
+
+/**
+ * enum nl80211_nan_func_attributes - NAN function attributes
+ * @__NL80211_NAN_FUNC_INVALID: invalid
+ * @NL80211_NAN_FUNC_TYPE: &enum nl80211_nan_function_type (u8).
+ * @NL80211_NAN_FUNC_SERVICE_ID: 6 bytes of the service ID hash as
+ *	specified in NAN spec. This is a binary attribute.
+ * @NL80211_NAN_FUNC_PUBLISH_TYPE: relevant if the function's type is
+ *	publish. Defines the transmission type for the publish Service Discovery
+ *	Frame, see &enum nl80211_nan_publish_type. Its type is u8.
+ * @NL80211_NAN_FUNC_PUBLISH_BCAST: relevant if the function's type is publish.
+ *	Should the publish Service Discovery Frame be sent in to NAN Broadcast
+ *	address. This is a flag.
+ * @NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE: relevant if the function's type is
+ *	subscribe. Is the subscribe active. This is a flag.
+ * @NL80211_NAN_FUNC_FOLLOW_UP_ID: relevant if the function's type is follow up.
+ *	The instance ID for the follow up Service Discovery Frame. This is u8.
+ * @NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID: relevant if the function's type
+ *	is follow up. This is a u8.
+ *	The requestor instance ID for the follow up Service Discovery Frame.
+ * @NL80211_NAN_FUNC_FOLLOW_UP_DEST: the MAC address of the recipient of the
+ *	follow up Service Discovery Frame. This is a binary attribute.
+ * @NL80211_NAN_FUNC_DISCOVERY_RANGE: is this function limited for devices in a
+ *	certain range. This is a flag.
+ * @NL80211_NAN_FUNC_TTL: number of DWs this function should stay active. 0 is
+ *	equivalent to no TTL at all. This is a u32.
+ * @NL80211_NAN_FUNC_SERVICE_INFO: array of bytes describing the service
+ *	specific info. This is a binary attribute.
+ * @NL80211_NAN_FUNC_SRF: Service Receive Filter. This is a nested attribute.
+ *	See &enum nl80211_nan_srf_attributes.
+ * @NL80211_NAN_FUNC_RX_MATCH_FILTER: Receive Matching filter. This is a nested
+ *	attribute. It is a list of binary values.
+ * @NL80211_NAN_FUNC_TX_MATCH_FILTER: Transmit Matching filter. This is a
+ *	nested attribute. It is a list of binary values.
+ * @NUM_NL80211_NAN_FUNC_ATTR: internal
+ * @NL80211_NAN_FUNC_ATTR_MAX: highest NAN function attribute
+ */
+enum nl80211_nan_func_attributes {
+	__NL80211_NAN_FUNC_INVALID,
+	NL80211_NAN_FUNC_TYPE,
+	NL80211_NAN_FUNC_SERVICE_ID,
+	NL80211_NAN_FUNC_PUBLISH_TYPE,
+	NL80211_NAN_FUNC_PUBLISH_BCAST,
+	NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE,
+	NL80211_NAN_FUNC_FOLLOW_UP_ID,
+	NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID,
+	NL80211_NAN_FUNC_FOLLOW_UP_DEST,
+	NL80211_NAN_FUNC_DISCOVERY_RANGE,
+	NL80211_NAN_FUNC_TTL,
+	NL80211_NAN_FUNC_SERVICE_INFO,
+	NL80211_NAN_FUNC_SRF,
+	NL80211_NAN_FUNC_RX_MATCH_FILTER,
+	NL80211_NAN_FUNC_TX_MATCH_FILTER,
+
+	/* keep last */
+	NUM_NL80211_NAN_FUNC_ATTR,
+	NL80211_NAN_FUNC_ATTR_MAX = NUM_NL80211_NAN_FUNC_ATTR - 1
+};
+
+/**
+ * enum nl80211_nan_srf_attributes - NAN Service Response filter attributes
+ * @__NL80211_NAN_SRF_INVALID: invalid
+ * @NL80211_NAN_SRF_INCLUDE: true if the include bit of the SRF set.
+ *	This is a flag.
+ * @NL80211_NAN_SRF_TYPE_BF: true if the SRF is a Bloom Filter SRF. If false
+ *	the SRF will be &NL80211_ATTR_MAC_ADDRS. This is a flag.
+ * @NL80211_NAN_SRF_BF: Bloom Filter. Relevant and mandatory if
+ *	&NL80211_NAN_SRF_TYPE_BF is true. This attribute is binary.
+ * @NL80211_NAN_SRF_BF_IDX: index of the Bloom Filter. Relevant and
+ *	mandatory if &NL80211_NAN_SRF_TYPE_BF is true. This is a u8.
+ * @NL80211_NAN_SRF_MAC_ADDRS: list of MAC addresses for the SRF. Relevant and
+ *	mandatory if &NL80211_NAN_SRF_TYPE_BF is false. This is a nested
+ *	attribute. Each nested attribute is a MAC address.
+ * @NUM_NL80211_NAN_SRF_ATTR: internal
+ * @NL80211_NAN_SRF_ATTR_MAX: highest NAN SRF attribute
+ */
+enum nl80211_nan_srf_attributes {
+	__NL80211_NAN_SRF_INVALID,
+	NL80211_NAN_SRF_INCLUDE,
+	NL80211_NAN_SRF_TYPE_BF,
+	NL80211_NAN_SRF_BF,
+	NL80211_NAN_SRF_BF_IDX,
+	NL80211_NAN_SRF_MAC_ADDRS,
+
+	/* keep last */
+	NUM_NL80211_NAN_SRF_ATTR,
+	NL80211_NAN_SRF_ATTR_MAX = NUM_NL80211_NAN_SRF_ATTR - 1,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 1a1fae0..e9e70ec 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -600,7 +600,8 @@ int wiphy_register(struct wiphy *wiphy)
 		return -EINVAL;
 
 	if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN)) &&
-		    (!rdev->ops->start_nan || !rdev->ops->stop_nan)))
+		    (!rdev->ops->start_nan || !rdev->ops->stop_nan ||
+		     !rdev->ops->add_nan_func || !rdev->ops->rm_nan_func)))
 		return -EINVAL;
 
 	/*
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 6992694..0cfe17d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -408,6 +408,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 	[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
 	[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
 	[NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
+	[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
+	[NL80211_ATTR_NAN_FUNC_INST_ID] = { .type = NLA_U8 },
 };
 
 /* policy for the key attributes */
@@ -486,6 +488,38 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
 	[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
 };
 
+/* policy for NAN function attributes */
+static const struct nla_policy
+nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
+	[NL80211_NAN_FUNC_TYPE] = { .type = NLA_U8 },
+	[NL80211_NAN_FUNC_SERVICE_ID] = { .type = NLA_BINARY,
+				    .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
+	[NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
+	[NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
+	[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
+	[NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
+	[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
+	[NL80211_NAN_FUNC_FOLLOW_UP_DEST] = { .len = ETH_ALEN },
+	[NL80211_NAN_FUNC_DISCOVERY_RANGE] = { .type = NLA_FLAG },
+	[NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
+	[NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
+					    .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
+	[NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
+	[NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
+	[NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
+};
+
+/* policy for Service Response Filter attributes */
+static const struct nla_policy
+nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
+	[NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
+	[NL80211_NAN_SRF_TYPE_BF] = { .type = NLA_FLAG },
+	[NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
+				 .len =  NL80211_NAN_FUNC_SRF_MAX_LEN },
+	[NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
+	[NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
+};
+
 static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
 				     struct netlink_callback *cb,
 				     struct cfg80211_registered_device **rdev,
@@ -9841,6 +9875,256 @@ static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
+static int validate_nan_filter(struct nlattr *filter_attr)
+{
+	struct nlattr *attr;
+	int len = 0, n_entries = 0, rem;
+
+	nla_for_each_nested(attr, filter_attr, rem) {
+		len += nla_len(attr);
+		n_entries++;
+	}
+
+	if (len >= U8_MAX)
+		return -EINVAL;
+
+	return n_entries;
+}
+
+static int handle_nan_filter(struct nlattr *attr_filter,
+			     struct cfg80211_nan_func *func,
+			     bool tx)
+{
+	struct nlattr *attr;
+	int n_entries, rem, i;
+	struct cfg80211_nan_func_filter *filter;
+
+	n_entries = validate_nan_filter(attr_filter);
+	if (n_entries < 0)
+		return -EINVAL;
+
+	BUILD_BUG_ON(sizeof(*func->rx_filters) != sizeof(*func->tx_filters));
+
+	filter = kcalloc(n_entries, sizeof(*func->rx_filters), GFP_KERNEL);
+	if (!filter)
+		return -ENOMEM;
+
+	i = 0;
+	nla_for_each_nested(attr, attr_filter, rem) {
+		filter[i].filter = nla_data(attr);
+		filter[i].len = nla_len(attr);
+		i++;
+	}
+	if (tx) {
+		func->num_tx_filters = n_entries;
+		func->tx_filters = filter;
+	} else {
+		func->num_rx_filters = n_entries;
+		func->rx_filters = filter;
+	}
+
+	return 0;
+}
+
+static int nl80211_nan_add_func(struct sk_buff *skb,
+				struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct wireless_dev *wdev = info->user_ptr[1];
+	struct nlattr *tb[NUM_NL80211_NAN_FUNC_ATTR];
+	struct cfg80211_nan_func func = {};
+	struct sk_buff *msg = NULL;
+	void *hdr = NULL;
+	int err, inst_id = 0;
+
+	if (wdev->iftype != NL80211_IFTYPE_NAN)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_NAN_FUNC])
+		return -EINVAL;
+
+	err = nla_parse(tb, NL80211_NAN_FUNC_ATTR_MAX,
+			nla_data(info->attrs[NL80211_ATTR_NAN_FUNC]),
+			nla_len(info->attrs[NL80211_ATTR_NAN_FUNC]),
+			nl80211_nan_func_policy);
+
+	if (err)
+		return err;
+
+	if (!tb[NL80211_NAN_FUNC_TYPE] ||
+	    nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]) >= NL80211_NAN_FUNC_MAX_TYPE)
+		return -EINVAL;
+
+	func.type = nla_get_u8(tb[NL80211_NAN_FUNC_TYPE]);
+
+	if (!tb[NL80211_NAN_FUNC_SERVICE_ID])
+		return -EINVAL;
+
+	memcpy(func.service_id, nla_data(tb[NL80211_NAN_FUNC_SERVICE_ID]),
+	       sizeof(func.service_id));
+
+	func.discovery_range =
+		nla_get_flag(tb[NL80211_NAN_FUNC_DISCOVERY_RANGE]);
+
+	if (tb[NL80211_NAN_FUNC_SERVICE_INFO]) {
+		func.serv_spec_info_len =
+			nla_len(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
+		func.serv_spec_info =
+			nla_data(tb[NL80211_NAN_FUNC_SERVICE_INFO]);
+	}
+
+	if (tb[NL80211_NAN_FUNC_TTL])
+		func.ttl = nla_get_u32(tb[NL80211_NAN_FUNC_TTL]);
+
+	switch (func.type) {
+	case NL80211_NAN_FUNC_PUBLISH:
+		if (!tb[NL80211_NAN_FUNC_PUBLISH_TYPE])
+			return -EINVAL;
+
+		func.publish_type = nla_get_u8(tb[NL80211_NAN_FUNC_PUBLISH_TYPE]);
+		func.publish_bcast =
+			nla_get_flag(tb[NL80211_NAN_FUNC_PUBLISH_BCAST]);
+
+		if ((!(func.publish_type & NL80211_NAN_SOLICITED_PUBLISH)) &&
+		    func.publish_bcast)
+			return -EINVAL;
+		break;
+	case NL80211_NAN_FUNC_SUBSCRIBE:
+		func.subscribe_active =
+			nla_get_flag(tb[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE]);
+		break;
+	case NL80211_NAN_FUNC_FOLLOW_UP:
+		if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] ||
+		    !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID])
+			return -EINVAL;
+
+		func.followup_id =
+			nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_ID]);
+		func.followup_reqid =
+			nla_get_u8(tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]);
+		memcpy(func.followup_dest.addr,
+		       nla_data(tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]),
+		       sizeof(func.followup_dest.addr));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (tb[NL80211_NAN_FUNC_SRF]) {
+		struct nlattr *srf_tb[NUM_NL80211_NAN_SRF_ATTR];
+
+		err = nla_parse(srf_tb, NL80211_NAN_SRF_ATTR_MAX,
+				nla_data(tb[NL80211_NAN_FUNC_SRF]),
+				nla_len(tb[NL80211_NAN_FUNC_SRF]), NULL);
+		if (err)
+			return err;
+
+		func.srf_include =
+			nla_get_flag(srf_tb[NL80211_NAN_SRF_INCLUDE]);
+
+		if (nla_get_flag(srf_tb[NL80211_NAN_SRF_TYPE_BF])) {
+			if (!srf_tb[NL80211_NAN_SRF_BF] ||
+			    !srf_tb[NL80211_NAN_SRF_BF_IDX])
+				return -EINVAL;
+
+			func.srf_bf_len =
+				nla_len(srf_tb[NL80211_NAN_SRF_TYPE_BF]);
+			func.srf_bf =
+				nla_data(srf_tb[NL80211_NAN_SRF_TYPE_BF]);
+			func.srf_bf_idx =
+				nla_get_u8(srf_tb[NL80211_NAN_SRF_BF_IDX]);
+		} else {
+			struct nlattr *attr, *mac_attr =
+				srf_tb[NL80211_NAN_SRF_MAC_ADDRS];
+			int n_entries, rem, i = 0;
+
+			if (!mac_attr)
+				return -EINVAL;
+
+			n_entries = validate_acl_mac_addrs(mac_attr);
+			if (n_entries <= 0)
+				return -EINVAL;
+
+			func.srf_num_macs = n_entries;
+			func.srf_macs =
+				kzalloc(sizeof(*func.srf_macs) * n_entries,
+					GFP_KERNEL);
+			if (!func.srf_macs)
+				return -ENOMEM;
+
+			nla_for_each_nested(attr, mac_attr, rem)
+				memcpy(func.srf_macs[i++].addr, nla_data(attr),
+				       sizeof(*func.srf_macs));
+		}
+	}
+
+	err = handle_nan_filter(tb[NL80211_NAN_FUNC_TX_MATCH_FILTER],
+				&func, true);
+	if (err)
+		goto out;
+
+	err = handle_nan_filter(tb[NL80211_NAN_FUNC_RX_MATCH_FILTER],
+				&func, false);
+	if (err)
+		goto out;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	hdr = nl80211hdr_put(msg, genl_info_snd_portid(info), info->snd_seq, 0,
+			     NL80211_CMD_ADD_NAN_FUNCTION);
+	/* This can't really happen - we just allocated 4KB */
+	if (WARN_ON(!hdr)) {
+		err = -ENOBUFS;
+		goto out;
+	}
+
+	inst_id = rdev_add_nan_func(rdev, wdev, &func);
+out:
+	kfree(func.srf_macs);
+	kfree(func.rx_filters);
+	kfree(func.tx_filters);
+
+	if (inst_id < 0) {
+		nlmsg_free(msg);
+		return inst_id;
+	}
+
+	/* propagate the instance id to userspace  */
+	if (WARN_ON(nla_put_u8(msg, NL80211_ATTR_NAN_FUNC_INST_ID, inst_id)))
+		err = -ENOBUFS;
+
+	if (hdr && msg) {
+		genlmsg_end(msg, hdr);
+		err = genlmsg_reply(msg, info);
+	}
+
+	return err;
+}
+
+static int nl80211_nan_rm_func(struct sk_buff *skb,
+			       struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct wireless_dev *wdev = info->user_ptr[1];
+	u8 instance_id;
+
+	if (wdev->iftype != NL80211_IFTYPE_NAN)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_NAN_FUNC_INST_ID])
+		return -EINVAL;
+
+	instance_id = nla_get_u8(info->attrs[NL80211_ATTR_NAN_FUNC_INST_ID]);
+
+	rdev_rm_nan_func(rdev, wdev, instance_id);
+
+	return 0;
+}
+
 static int nl80211_get_protocol_features(struct sk_buff *skb,
 					 struct genl_info *info)
 {
@@ -11005,6 +11289,22 @@ static __genl_const struct genl_ops nl80211_ops[] = {
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
+		.cmd = NL80211_CMD_ADD_NAN_FUNCTION,
+		.doit = nl80211_nan_add_func,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_RM_NAN_FUNCTION,
+		.doit = nl80211_nan_rm_func,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
 		.cmd = NL80211_CMD_SET_MCAST_RATE,
 		.doit = nl80211_set_mcast_rate,
 		.policy = nl80211_policy,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 593fbb7..9a42c92 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -895,6 +895,28 @@ static inline void rdev_stop_nan(struct cfg80211_registered_device *rdev,
 	trace_rdev_return_void(&rdev->wiphy);
 }
 
+static inline int
+rdev_add_nan_func(struct cfg80211_registered_device *rdev,
+		  struct wireless_dev *wdev,
+		  const struct cfg80211_nan_func *nan_func)
+{
+	int ret;
+
+	trace_rdev_add_nan_func(&rdev->wiphy, wdev, nan_func);
+	ret = rdev->ops->add_nan_func(&rdev->wiphy, wdev, nan_func);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
+static inline void rdev_rm_nan_func(struct cfg80211_registered_device *rdev,
+				    struct wireless_dev *wdev,
+				    u8 instance_id)
+{
+	trace_rdev_rm_nan_func(&rdev->wiphy, wdev, instance_id);
+	rdev->ops->rm_nan_func(&rdev->wiphy, wdev, instance_id);
+	trace_rdev_return_void(&rdev->wiphy);
+}
+
 static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
 				   struct net_device *dev,
 				   struct cfg80211_acl_data *params)
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 3718563..a0de576 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1877,6 +1877,42 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_nan,
 	TP_ARGS(wiphy, wdev)
 );
 
+TRACE_EVENT(rdev_add_nan_func,
+	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+		 const struct cfg80211_nan_func *func),
+	TP_ARGS(wiphy, wdev, func),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		WDEV_ENTRY
+		__field(u8, func_type)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		WDEV_ASSIGN;
+		__entry->func_type = func->type;
+	),
+	TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type=%u",
+		  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->func_type)
+);
+
+TRACE_EVENT(rdev_rm_nan_func,
+	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+		 u8 instance_id),
+	TP_ARGS(wiphy, wdev, instance_id),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		WDEV_ENTRY
+		__field(u8, instance_id)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		WDEV_ASSIGN;
+		__entry->instance_id = instance_id;
+	),
+	TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", instance id=%u",
+		  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->instance_id)
+);
+
 TRACE_EVENT(rdev_set_mac_acl,
 	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
 		 struct cfg80211_acl_data *params),
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC 4/5] cfg80211: allow the user space to change the NAN master preference
  2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
                   ` (2 preceding siblings ...)
  2015-03-30 14:14 ` [RFC 3/5] cfg80211: add add_nan_func / rm_nan_func Emmanuel Grumbach
@ 2015-03-30 14:14 ` Emmanuel Grumbach
  2015-03-30 14:14 ` [RFC 5/5] cfg80211: provide a function to report a match for NAN Emmanuel Grumbach
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-03-30 14:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach

This can be useful if the device get plugged / unplugged
to the power. Update the driver when the master preference
is updated and make it optional.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
 include/net/cfg80211.h       |  4 ++++
 include/uapi/linux/nl80211.h |  4 ++++
 net/wireless/nl80211.c       | 28 ++++++++++++++++++++++++++++
 net/wireless/rdev-ops.h      | 16 ++++++++++++++++
 net/wireless/trace.h         | 18 ++++++++++++++++++
 5 files changed, 70 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 64f45a9..56ed869 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2434,6 +2434,7 @@ struct cfg80211_nan_func {
  *	upon success. The data in cfg80211_nan_func must not be referenced
  *	outside the scope of this call.
  * @rm_nan_func: Remove a nan function
+ * @nan_change_master_pref: changes the NAN master preference.
  *
  * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
  *	Parameters include ACL policy, an array of MAC address of stations
@@ -2759,6 +2760,9 @@ struct cfg80211_ops {
 				const struct cfg80211_nan_func *nan_func);
 	void	(*rm_nan_func)(struct wiphy *wiphy, struct wireless_dev *wdev,
 				   u8 instance_id);
+	int	(*nan_change_master_pref)(struct wiphy *wiphy,
+					  struct wireless_dev *wdev,
+					  u8 master_pref);
 };
 
 /*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index b3bf9aa..471879d 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -812,6 +812,9 @@
  *	the function upon success.
  * @NL80211_CMD_RM_NAN_FUNCTION: remove a NAN function based on its instance
  *	id.
+ * @NL80211_CMD_CHANGE_NAN_MASTER_PREF: Changes the master preference while NAN
+ *	is operational. It must contain a valid %NL80211_ATTR_NAN_MASTER_PREF
+ *	attribute.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -1003,6 +1006,7 @@ enum nl80211_commands {
 	NL80211_CMD_STOP_NAN,
 	NL80211_CMD_ADD_NAN_FUNCTION,
 	NL80211_CMD_RM_NAN_FUNCTION,
+	NL80211_CMD_CHANGE_NAN_MASTER_PREF,
 
 	/* add new commands above here */
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0cfe17d..f1cd4e3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10125,6 +10125,26 @@ static int nl80211_nan_rm_func(struct sk_buff *skb,
 	return 0;
 }
 
+static int nl80211_nan_change_master_pref(struct sk_buff *skb,
+					  struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct wireless_dev *wdev = info->user_ptr[1];
+	u8 master_pref;
+
+	if (wdev->iftype != NL80211_IFTYPE_NAN)
+		return -EOPNOTSUPP;
+
+	if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
+		return -EINVAL;
+
+	master_pref = nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
+	if (master_pref <= 1 || master_pref == 255)
+		return -EINVAL;
+
+	return rdev_nan_change_master_pref(rdev, wdev, master_pref);
+}
+
 static int nl80211_get_protocol_features(struct sk_buff *skb,
 					 struct genl_info *info)
 {
@@ -11305,6 +11325,14 @@ static __genl_const struct genl_ops nl80211_ops[] = {
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
+		.cmd = NL80211_CMD_CHANGE_NAN_MASTER_PREF,
+		.doit = nl80211_nan_change_master_pref,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
 		.cmd = NL80211_CMD_SET_MCAST_RATE,
 		.doit = nl80211_set_mcast_rate,
 		.policy = nl80211_policy,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 9a42c92..2cad83c 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -917,6 +917,22 @@ static inline void rdev_rm_nan_func(struct cfg80211_registered_device *rdev,
 	trace_rdev_return_void(&rdev->wiphy);
 }
 
+static inline int
+rdev_nan_change_master_pref(struct cfg80211_registered_device *rdev,
+			    struct wireless_dev *wdev, u8 master_pref)
+{
+	int ret;
+
+	trace_rdev_nan_change_master_pref(&rdev->wiphy, wdev, master_pref);
+	if (rdev->ops->nan_change_master_pref)
+		ret = rdev->ops->nan_change_master_pref(&rdev->wiphy, wdev,
+							master_pref);
+	else
+		ret = -ENOTSUPP;
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
 static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
 				   struct net_device *dev,
 				   struct cfg80211_acl_data *params)
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index a0de576..f264ac3 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1872,6 +1872,24 @@ TRACE_EVENT(rdev_start_nan,
 		  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->master_pref)
 );
 
+TRACE_EVENT(rdev_nan_change_master_pref,
+	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+		 u8 master_pref),
+	TP_ARGS(wiphy, wdev, master_pref),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		WDEV_ENTRY
+		__field(u8, master_pref)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		WDEV_ASSIGN;
+		__entry->master_pref = master_pref;
+	),
+	TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", master preference: %u",
+		  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->master_pref)
+);
+
 DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_nan,
 	TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
 	TP_ARGS(wiphy, wdev)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC 5/5] cfg80211: provide a function to report a match for NAN
  2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
                   ` (3 preceding siblings ...)
  2015-03-30 14:14 ` [RFC 4/5] cfg80211: allow the user space to change the NAN master preference Emmanuel Grumbach
@ 2015-03-30 14:14 ` Emmanuel Grumbach
       [not found] ` <CAEhWJFmknndcDTGQqBDYt=E_gvidKaDskvZUH1n1Hjce34akeg@mail.gmail.com>
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-03-30 14:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach

Provide a function the driver can call to report a match.
This will send the event to the user space.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
 include/net/cfg80211.h       | 24 +++++++++++++
 include/uapi/linux/nl80211.h | 37 ++++++++++++++++++++
 net/wireless/nl80211.c       | 82 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 56ed869..8913c2b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5192,6 +5192,30 @@ wiphy_ext_feature_isset(struct wiphy *wiphy,
 	return (ft_byte & BIT(ftidx % 8)) != 0;
 }
 
+/**
+ * cfg80211_nan_match - report a match for a NAN function.
+ * @wdev: the wireless device reporting the match
+ * @type: the type of the function that had a match. If it is
+ *	%NL80211_NAN_FUNC_SUBSCRIBE it means that we heard a publisher.
+ *	If it is %NL80211_NAN_FUNC_PUBLISH, it means that we replied to
+ *	an active subscriber with a solicited publish.
+ *	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: the Service Specific Info from the peer (if any)
+ * @info_len: the length of the &info
+ * @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,
+			enum nl80211_nan_function_type type,
+			u8 inst_id, u8 peer_inst_id, const u8 *addr,
+			const u8 *info, u8 info_len, gfp_t gfp);
+
 /* ethtool helper */
 void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
 
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 471879d..e9aaf1e 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -815,6 +815,8 @@
  * @NL80211_CMD_CHANGE_NAN_MASTER_PREF: Changes the master preference while NAN
  *	is operational. It must contain a valid %NL80211_ATTR_NAN_MASTER_PREF
  *	attribute.
+ * @NL80211_CMD_NAN_FUNC_MATCH: Notification sent when a match is reported.
+ *	This will contain a %NL80211_ATTR_NAN_MATCH nested attribute.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -1007,6 +1009,7 @@ enum nl80211_commands {
 	NL80211_CMD_ADD_NAN_FUNCTION,
 	NL80211_CMD_RM_NAN_FUNCTION,
 	NL80211_CMD_CHANGE_NAN_MASTER_PREF,
+	NL80211_CMD_NAN_MATCH,
 
 	/* add new commands above here */
 
@@ -1773,6 +1776,8 @@ enum nl80211_commands {
  *	attribute.
  * @NL80211_ATTR_NAN_FUNC_INST_ID: the instance id of a %NL80211_ATTR_NAN_FUNC.
  *	Its type is u8 and it cannot be 0.
+ * @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
@@ -2144,6 +2149,7 @@ enum nl80211_attrs {
 	NL80211_ATTR_NAN_MASTER_PREF,
 	NL80211_ATTR_NAN_FUNC,
 	NL80211_ATTR_NAN_FUNC_INST_ID,
+	NL80211_ATTR_NAN_MATCH,
 	
 	NL80211_ATTR_REG_INDOOR,
 
@@ -4728,4 +4734,35 @@ 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_TYPE: &enum nl80211_nan_function_type (u8). This is
+ *	the type of the function which had a match.
+ * @NL80211_NAN_MATCH_INSTANCE_ID: The instance ID of the local function that
+ *	had a match. This is a u8.
+ * @NL80211_NAN_MATCH_PEER_INSTANCE_ID: The instance ID of the peer's function
+ *	that caused the match. This is a u8.
+ *	specified in NAN spec. This is a binary attribute.
+ * @NL80211_NAN_MATCH_MAC: The MAC address of the peer. This attribute is
+ *	binary.
+ * @NL80211_NAN_MATCH_SERVICE_INFO: array of bytes describing the peer's
+ *	service specific info. This is a binary attribute.
+ *
+ * @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_TYPE,
+	NL80211_NAN_MATCH_INSTANCE_ID,
+	NL80211_NAN_MATCH_PEER_INSTANCE_ID,
+	NL80211_NAN_MATCH_MAC,
+	NL80211_NAN_MATCH_SERVICE_INFO,
+
+	/* keep last */
+	NUM_NL80211_NAN_MATCH_ATTR,
+	NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_FUNC_ATTR - 1
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f1cd4e3..22162d1 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -509,6 +509,20 @@ nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
 	[NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
 };
 
+/* policy for NAN match attributes */
+static const struct nla_policy
+nl80211_nan_match_policy[NL80211_NAN_MATCH_ATTR_MAX + 1] = {
+	[NL80211_NAN_MATCH_FUNC_TYPE] = { .type = NLA_U8 },
+	[NL80211_NAN_MATCH_INSTANCE_ID] = { .type = NLA_U8 },
+	[NL80211_NAN_MATCH_PEER_INSTANCE_ID] = { .type = NLA_U8 },
+	[NL80211_NAN_MATCH_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
+	[NL80211_NAN_MATCH_SERVICE_INFO] = {
+		.type = NLA_BINARY,
+		.len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN
+	},
+
+};
+
 /* policy for Service Response Filter attributes */
 static const struct nla_policy
 nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
@@ -10145,6 +10159,74 @@ static int nl80211_nan_change_master_pref(struct sk_buff *skb,
 	return rdev_nan_change_master_pref(rdev, wdev, master_pref);
 }
 
+static void
+nl80211_send_nan_match(struct cfg80211_registered_device *rdev,
+		       struct wireless_dev *wdev,
+		       enum nl80211_nan_function_type type,
+		       u8 inst_id, u8 peer_inst_id, const u8 *addr,
+		       const u8 *info, u8 info_len, gfp_t gfp)
+{
+	struct nlattr *match;
+	struct sk_buff *msg;
+	void *hdr;
+
+	if (WARN_ON(!inst_id || !peer_inst_id || !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(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
+		goto nla_put_failure;
+
+	match = nla_nest_start(msg, NL80211_ATTR_NAN_MATCH);
+	if (!match)
+		goto nla_put_failure;
+
+	if (nla_put_u8(msg, NL80211_NAN_MATCH_FUNC_TYPE, type) ||
+	    nla_put_u8(msg, NL80211_NAN_MATCH_INSTANCE_ID, inst_id) ||
+	    nla_put_u8(msg, NL80211_NAN_MATCH_PEER_INSTANCE_ID, peer_inst_id) ||
+	    nla_put(msg, NL80211_NAN_MATCH_MAC, ETH_ALEN, addr))
+		goto nla_put_failure;
+
+	if (info && info_len &&
+	    nla_put(msg, NL80211_NAN_MATCH_SERVICE_INFO, info_len, info))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+				NL80211_MCGRP_MLME, gfp);
+	return;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
+void cfg80211_nan_match(struct wireless_dev *wdev,
+			enum nl80211_nan_function_type type,
+			u8 inst_id, u8 peer_inst_id, const u8 *addr,
+			const u8 *info, u8 info_len, gfp_t gfp)
+{
+	struct wiphy *wiphy = wdev->wiphy;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+	nl80211_send_nan_match(rdev, wdev, type, inst_id, peer_inst_id, addr,
+			       info, info_len, gfp);
+}
+EXPORT_SYMBOL(cfg80211_nan_match);
+
 static int nl80211_get_protocol_features(struct sk_buff *skb,
 					 struct genl_info *info)
 {
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking
       [not found]     ` <f32f47395b524017b58306d770b020a6@SC-EXCH04.marvell.com>
@ 2015-06-26  8:22       ` Grumbach, Emmanuel
  0 siblings, 0 replies; 12+ messages in thread
From: Grumbach, Emmanuel @ 2015-06-26  8:22 UTC (permalink / raw)
  To: akarwar; +Cc: linux-wireless

T24gRnJpLCAyMDE1LTA2LTI2IGF0IDA2OjA2ICswMDAwLCBBbWl0a3VtYXIgS2Fyd2FyIHdyb3Rl
Og0KPiBIaSBFbW1hbnVlbCwNCj4gDQo+ID4gRnJvbTogRW1tYW51ZWwgR3J1bWJhY2ggPGVtbWFu
dWVsLmdydW1iYWNoQGludGVsLmNvbT4NCj4gPiBEYXRlOiBNb24sIE1hciAzMCwgMjAxNSBhdCA3
OjQ0IFBNDQo+ID4gU3ViamVjdDogW1JGQyAwLzVdIGNmZzgwMjExIC8gbWFjODAyMTE6IGFkZCBz
dXBwb3J0IGZvciBOZWlnaGJvcg0KPiA+IEF3YXJlbmVzcyBOZXR3b3JraW5nDQo+ID4gVG86IGxp
bnV4LXdpcmVsZXNzQHZnZXIua2VybmVsLm9yZw0KPiA+IENjOiBFbW1hbnVlbCBHcnVtYmFjaCA8
ZW1tYW51ZWwuZ3J1bWJhY2hAaW50ZWwuY29tPg0KPiA+IA0KPiA+IA0KPiA+IFRoaXMgcGF0Y2gg
c2VyaWVzIGFkZCBzdXBwb3J0cyBmb3IgYSBuZXcgV2lGaSBmZWF0dXJlIGNhbGxlZA0KPiA+IE5l
aWdoYm9yIEF3YXJlbmVzcyBOZXR3b3JraW5nIGEuay5hLiBOQU4uDQo+ID4gSXQgaXMgYnVpbHQg
ZnJvbSB0aGUgZm9sbG93aW5nIGxheWVyczoNCj4gPiAgKiBUaW1lIHN5bmNocm9uaXphdGlvbg0K
PiA+ICAqIERpc2NvdmVyeSBFbmdpbmUgKERFKQ0KPiA+IA0KPiANCj4gV2Ugd2VyZSBpbnRlcmVz
dGVkIGluIHN1cHBvcnRpbmcgTkFOIGZlYXR1cmUgaW4gb3VyIFdMQU4gZHJpdmVyLiBJIGNhbWUg
YWNyb3NzIHRoaXMgUkZDIHBhdGNoIHNlcmllcyBwb3N0ZWQgY291cGxlIG9mIG1vbnRocyBiYWNr
LiBEbyB5b3UgaGF2ZSBhbnkgcGxhbiB0byBzdWJtaXQgdGhlIHVwZGF0ZWQgdmVyc2lvbj8gTGV0
IHVzIGtub3cgaWYgd2UgY2FuIGNvbnRyaWJ1dGUgdG8gaXQgaW4gYW55IHdheS4NCg0KT2sgLSBu
b3cgdGhhdCB0aGUgdGVjaG5vbG9neSBoYXMgYWxtb3N0IGxhdW5jaGVkLCBJIGd1ZXNzIHdlIHdp
bGwgc2VlDQptb3JlIGludGVyZXN0LiBJIGd1ZXNzIHdlIGNhbiByZXN1Ym1pdCBpdCwgYnV0IHdl
IG5lZWQgdG8gdGhpbmsNCmNhcmVmdWxseSBhYm91dCBob3cgdGhlIEFQSSBzaG91bGQgbG9vayBs
aWtlLiBUaGlzIHBhcnQgaXNuJ3QgdHJpdmlhbCBhdA0KYWxsIHNpbmNlIHRoZSBlY29zeXN0ZW0g
aXNuJ3Qgd2VsbCBkZWZpbmVkICh0byBzYXkgdGhlIGxlYXN0KS4gU28gSSBhbQ0Ka2luZGEgYWZy
YWlkIHRoYXQgd2Ugd2lsbCBkZWZpbmUgc29tZXRoaW5nIHRoYXQgd2lsbCBub3Qgc3VpdCBvdXIg
bmVlZHMNCndoZW4gdGhlIHVzZXJzcGFjZSB3aWxsIGJlZ2luIHRvIGhhdmUgY2xlYXJlciByZXF1
aXJlbWVudHMuDQpJIHdvbid0IHN0YW5kIGluIHRoZSB3YXkgaWYgeW91IHdhbnQgdG8gcmV2aXZl
IHRoaXMgcGF0Y2ggc2VyaWVzIHRob3VnaC4NCg==

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking
  2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
                   ` (5 preceding siblings ...)
       [not found] ` <CAEhWJFmknndcDTGQqBDYt=E_gvidKaDskvZUH1n1Hjce34akeg@mail.gmail.com>
@ 2015-07-23 23:59 ` QH
  2015-07-24  3:53   ` Emmanuel Grumbach
  2015-08-26 17:17 ` Emmanuel Grumbach
  7 siblings, 1 reply; 12+ messages in thread
From: QH @ 2015-07-23 23:59 UTC (permalink / raw)
  To: linux-wireless

Emmanuel Grumbach <emmanuel.grumbach@...> writes:


++++++++++++++++++++++++++++++++++++++++++-
>  net/wireless/rdev-ops.h      |  57 +++++
>  net/wireless/trace.h         |  77 +++++++
>  net/wireless/util.c          |   9 +-
>  19 files changed, 1126 insertions(+), 11 deletions(-)
> 

where can I get these patches?

thanks,





^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking
  2015-07-23 23:59 ` QH
@ 2015-07-24  3:53   ` Emmanuel Grumbach
  2015-07-24  3:59     ` Emmanuel Grumbach
  0 siblings, 1 reply; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-07-24  3:53 UTC (permalink / raw)
  To: QH; +Cc: linux-wireless

On Fri, Jul 24, 2015 at 2:59 AM, QH <qiumin.hu@gmail.com> wrote:
>
> Emmanuel Grumbach <emmanuel.grumbach@...> writes:
>
>
> ++++++++++++++++++++++++++++++++++++++++++-
> >  net/wireless/rdev-ops.h      |  57 +++++
> >  net/wireless/trace.h         |  77 +++++++
> >  net/wireless/util.c          |   9 +-
> >  19 files changed, 1126 insertions(+), 11 deletions(-)
> >
>
> where can I get these patches?
>
> thanks,

These patches were't merged because they were sent as an RFC only. The
API towards the OS aren't clear (to me) yet, so it seems a bit
premature to build the user space API for that. But this RFC series
looks like a good start.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking
  2015-07-24  3:53   ` Emmanuel Grumbach
@ 2015-07-24  3:59     ` Emmanuel Grumbach
  2015-07-24  7:45       ` Emmanuel Grumbach
  0 siblings, 1 reply; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-07-24  3:59 UTC (permalink / raw)
  To: QH; +Cc: linux-wireless

On Fri, Jul 24, 2015 at 6:53 AM, Emmanuel Grumbach <egrumbach@gmail.com> wrote:
> On Fri, Jul 24, 2015 at 2:59 AM, QH <qiumin.hu@gmail.com> wrote:
>>
>> Emmanuel Grumbach <emmanuel.grumbach@...> writes:
>>
>>
>> ++++++++++++++++++++++++++++++++++++++++++-
>> >  net/wireless/rdev-ops.h      |  57 +++++
>> >  net/wireless/trace.h         |  77 +++++++
>> >  net/wireless/util.c          |   9 +-
>> >  19 files changed, 1126 insertions(+), 11 deletions(-)
>> >
>>
>> where can I get these patches?
>>
>> thanks,
>
> These patches were't merged because they were sent as an RFC only. The
> API towards the OS aren't clear (to me) yet, so it seems a bit
> premature to build the user space API for that. But this RFC series
> looks like a good start.

You can always apply the patches on your kernel source if you want
though. You can find them in patchwork, or alike.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking
  2015-07-24  3:59     ` Emmanuel Grumbach
@ 2015-07-24  7:45       ` Emmanuel Grumbach
  0 siblings, 0 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-07-24  7:45 UTC (permalink / raw)
  To: QH; +Cc: linux-wireless

On Fri, Jul 24, 2015 at 6:59 AM, Emmanuel Grumbach <egrumbach@gmail.com> wrote:
> On Fri, Jul 24, 2015 at 6:53 AM, Emmanuel Grumbach <egrumbach@gmail.com> wrote:
>> On Fri, Jul 24, 2015 at 2:59 AM, QH <qiumin.hu@gmail.com> wrote:
>>>
>>> Emmanuel Grumbach <emmanuel.grumbach@...> writes:
>>>
>>>
>>> ++++++++++++++++++++++++++++++++++++++++++-
>>> >  net/wireless/rdev-ops.h      |  57 +++++
>>> >  net/wireless/trace.h         |  77 +++++++
>>> >  net/wireless/util.c          |   9 +-
>>> >  19 files changed, 1126 insertions(+), 11 deletions(-)
>>> >
>>>
>>> where can I get these patches?
>>>
>>> thanks,
>>
>> These patches were't merged because they were sent as an RFC only. The
>> API towards the OS aren't clear (to me) yet, so it seems a bit
>> premature to build the user space API for that. But this RFC series
>> looks like a good start.
>
> You can always apply the patches on your kernel source if you want
> though. You can find them in patchwork, or alike.

One more thing - since you seem to be interested / know about NAN, I'd
love to get your insight about the proposed API.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking
  2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
                   ` (6 preceding siblings ...)
  2015-07-23 23:59 ` QH
@ 2015-08-26 17:17 ` Emmanuel Grumbach
  7 siblings, 0 replies; 12+ messages in thread
From: Emmanuel Grumbach @ 2015-08-26 17:17 UTC (permalink / raw)
  To: Emmanuel Grumbach; +Cc: linux-wireless, Qiumin Hu

On Mon, Mar 30, 2015 at 5:14 PM, Emmanuel Grumbach
<emmanuel.grumbach@intel.com> wrote:
> This patch series add supports for a new WiFi feature called
> Neighbor Awareness Networking a.k.a. NAN.

Quite a few people contacted me on that matter. Several contacted me
privately, others through IRC.
I am not sending this series as PATCH since we are not ready on the
driver level. And we typically don't want to have APIs that nobody
uses. iwlwifi should start supporting NAN early next year (no
commitment whatsoever of course).
Since I had no comments on this, I think the API is pretty much ready
which means that if some courageous application developer wants to
start using NAN, I think he can that he can take a decently safe
assumption that the API will look as described in this patch series.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-08-26 17:17 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-30 14:14 [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Emmanuel Grumbach
2015-03-30 14:14 ` [RFC 1/5] cfg80211: add start / stop NAN commands Emmanuel Grumbach
2015-03-30 14:14 ` [RFC 2/5] mac80211: add boilerplate code for start / stop NAN Emmanuel Grumbach
2015-03-30 14:14 ` [RFC 3/5] cfg80211: add add_nan_func / rm_nan_func Emmanuel Grumbach
2015-03-30 14:14 ` [RFC 4/5] cfg80211: allow the user space to change the NAN master preference Emmanuel Grumbach
2015-03-30 14:14 ` [RFC 5/5] cfg80211: provide a function to report a match for NAN Emmanuel Grumbach
     [not found] ` <CAEhWJFmknndcDTGQqBDYt=E_gvidKaDskvZUH1n1Hjce34akeg@mail.gmail.com>
     [not found]   ` <3436b448ddbc42b497e221870a96542d@SC-EXCH04.marvell.com>
     [not found]     ` <f32f47395b524017b58306d770b020a6@SC-EXCH04.marvell.com>
2015-06-26  8:22       ` [RFC 0/5] cfg80211 / mac80211: add support for Neighbor Awareness Networking Grumbach, Emmanuel
2015-07-23 23:59 ` QH
2015-07-24  3:53   ` Emmanuel Grumbach
2015-07-24  3:59     ` Emmanuel Grumbach
2015-07-24  7:45       ` Emmanuel Grumbach
2015-08-26 17:17 ` Emmanuel Grumbach

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.