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

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
...@@ -5854,6 +5854,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, ...@@ -5854,6 +5854,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
enum nl80211_commands cmd, enum nl80211_commands cmd,
enum nl80211_attrs attr, enum nl80211_attrs attr,
unsigned int portid,
int vendor_event_idx, int vendor_event_idx,
int approxlen, gfp_t gfp); int approxlen, gfp_t gfp);
...@@ -5903,6 +5904,15 @@ cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen) ...@@ -5903,6 +5904,15 @@ cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
*/ */
int cfg80211_vendor_cmd_reply(struct sk_buff *skb); 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 * cfg80211_vendor_event_alloc - allocate vendor-specific event skb
* @wiphy: the wiphy * @wiphy: the wiphy
...@@ -5930,7 +5940,42 @@ cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev, ...@@ -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, return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
NL80211_ATTR_VENDOR_DATA, 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 * ...@@ -6030,7 +6075,7 @@ static inline struct sk_buff *
cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp) cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
{ {
return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE, return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE,
NL80211_ATTR_TESTDATA, -1, NL80211_ATTR_TESTDATA, 0, -1,
approxlen, gfp); approxlen, gfp);
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015-2017 Intel Deutschland GmbH * Copyright 2015-2017 Intel Deutschland GmbH
* Copyright (C) 2018 Intel Corporation * Copyright (C) 2018-2019 Intel Corporation
*/ */
#include <linux/if.h> #include <linux/if.h>
...@@ -9306,6 +9306,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, ...@@ -9306,6 +9306,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
enum nl80211_commands cmd, enum nl80211_commands cmd,
enum nl80211_attrs attr, enum nl80211_attrs attr,
unsigned int portid,
int vendor_event_idx, int vendor_event_idx,
int approxlen, gfp_t gfp) int approxlen, gfp_t gfp)
{ {
...@@ -9329,7 +9330,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy, ...@@ -9329,7 +9330,7 @@ struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
return NULL; 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); cmd, attr, info, gfp);
} }
EXPORT_SYMBOL(__cfg80211_alloc_event_skb); EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
...@@ -9338,6 +9339,7 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp) ...@@ -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]; struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
void *hdr = ((void **)skb->cb)[1]; void *hdr = ((void **)skb->cb)[1];
struct nlmsghdr *nlhdr = nlmsg_hdr(skb);
struct nlattr *data = ((void **)skb->cb)[2]; struct nlattr *data = ((void **)skb->cb)[2];
enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE; enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
...@@ -9347,11 +9349,16 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp) ...@@ -9347,11 +9349,16 @@ void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
nla_nest_end(skb, data); nla_nest_end(skb, data);
genlmsg_end(skb, hdr); genlmsg_end(skb, hdr);
if (data->nla_type == NL80211_ATTR_VENDOR_DATA) if (nlhdr->nlmsg_pid) {
mcgrp = NL80211_MCGRP_VENDOR; 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, genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy),
mcgrp, gfp); skb, 0, mcgrp, gfp);
}
} }
EXPORT_SYMBOL(__cfg80211_send_event_skb); EXPORT_SYMBOL(__cfg80211_send_event_skb);
...@@ -12736,6 +12743,17 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb) ...@@ -12736,6 +12743,17 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
} }
EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply); 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, static int nl80211_set_qos_map(struct sk_buff *skb,
struct genl_info *info) struct genl_info *info)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment