Commit 55c1fdf0 authored by Johannes Berg's avatar Johannes Berg
Browse files

cfg80211: allow sending vendor events unicast



Sometimes, we may want to transport higher bandwidth data
through vendor events, and in that case sending it multicast
is a bad idea. Allow vendor events to be unicast.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 7976b1e9
Loading
Loading
Loading
Loading
+47 −2
Original line number Diff line number Diff line
@@ -5854,6 +5854,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
					   struct wireless_dev *wdev,
					   enum nl80211_commands cmd,
					   enum nl80211_attrs attr,
					   unsigned int portid,
					   int vendor_event_idx,
					   int approxlen, gfp_t gfp);

@@ -5903,6 +5904,15 @@ cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
 */
int cfg80211_vendor_cmd_reply(struct sk_buff *skb);

/**
 * cfg80211_vendor_cmd_get_sender
 * @wiphy: the wiphy
 *
 * Return the current netlink port ID in a vendor command handler.
 * Valid to call only there.
 */
unsigned int cfg80211_vendor_cmd_get_sender(struct wiphy *wiphy);

/**
 * cfg80211_vendor_event_alloc - allocate vendor-specific event skb
 * @wiphy: the wiphy
@@ -5930,7 +5940,42 @@ cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev,
{
	return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
					  NL80211_ATTR_VENDOR_DATA,
					  event_idx, approxlen, gfp);
					  0, event_idx, approxlen, gfp);
}

/**
 * cfg80211_vendor_event_alloc_ucast - alloc unicast vendor-specific event skb
 * @wiphy: the wiphy
 * @wdev: the wireless device
 * @event_idx: index of the vendor event in the wiphy's vendor_events
 * @portid: port ID of the receiver
 * @approxlen: an upper bound of the length of the data that will
 *	be put into the skb
 * @gfp: allocation flags
 *
 * This function allocates and pre-fills an skb for an event to send to
 * a specific (userland) socket. This socket would previously have been
 * obtained by cfg80211_vendor_cmd_get_sender(), and the caller MUST take
 * care to register a netlink notifier to see when the socket closes.
 *
 * If wdev != NULL, both the ifindex and identifier of the specified
 * wireless device are added to the event message before the vendor data
 * attribute.
 *
 * When done filling the skb, call cfg80211_vendor_event() with the
 * skb to send the event.
 *
 * Return: An allocated and pre-filled skb. %NULL if any errors happen.
 */
static inline struct sk_buff *
cfg80211_vendor_event_alloc_ucast(struct wiphy *wiphy,
				  struct wireless_dev *wdev,
				  unsigned int portid, int approxlen,
				  int event_idx, gfp_t gfp)
{
	return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
					  NL80211_ATTR_VENDOR_DATA,
					  portid, event_idx, approxlen, gfp);
}

/**
@@ -6030,7 +6075,7 @@ static inline struct sk_buff *
cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
{
	return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE,
					  NL80211_ATTR_TESTDATA, -1,
					  NL80211_ATTR_TESTDATA, 0, -1,
					  approxlen, gfp);
}

+24 −6
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 * Copyright 2006-2010	Johannes Berg <johannes@sipsolutions.net>
 * Copyright 2013-2014  Intel Mobile Communications GmbH
 * Copyright 2015-2017	Intel Deutschland GmbH
 * Copyright (C) 2018 Intel Corporation
 * Copyright (C) 2018-2019 Intel Corporation
 */

#include <linux/if.h>
@@ -9306,6 +9306,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
					   struct wireless_dev *wdev,
					   enum nl80211_commands cmd,
					   enum nl80211_attrs attr,
					   unsigned int portid,
					   int vendor_event_idx,
					   int approxlen, gfp_t gfp)
{
@@ -9329,7 +9330,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
		return NULL;
	}

	return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
	return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, portid, 0,
					   cmd, attr, info, gfp);
}
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
@@ -9338,6 +9339,7 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
{
	struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
	void *hdr = ((void **)skb->cb)[1];
	struct nlmsghdr *nlhdr = nlmsg_hdr(skb);
	struct nlattr *data = ((void **)skb->cb)[2];
	enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;

@@ -9347,11 +9349,16 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
	nla_nest_end(skb, data);
	genlmsg_end(skb, hdr);

	if (nlhdr->nlmsg_pid) {
		genlmsg_unicast(wiphy_net(&rdev->wiphy), skb,
				nlhdr->nlmsg_pid);
	} else {
		if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
			mcgrp = NL80211_MCGRP_VENDOR;

	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
				mcgrp, gfp);
		genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
					skb, 0, mcgrp, gfp);
	}
}
EXPORT_SYMBOL(__cfg80211_send_event_skb);

@@ -12736,6 +12743,17 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);

unsigned int cfg80211_vendor_cmd_get_sender(struct wiphy *wiphy)
{
	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);

	if (WARN_ON(!rdev->cur_cmd_info))
		return 0;

	return rdev->cur_cmd_info->snd_portid;
}
EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_get_sender);

static int nl80211_set_qos_map(struct sk_buff *skb,
			       struct genl_info *info)
{