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: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Родитель
7976b1e9e3
Коммит
55c1fdf0d6
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче