aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-12-18 08:43:31 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-19 07:40:31 -0500
commit567ffc3509b2d3f965a49a18631d3da7f9a96d4f (patch)
tree844230d68e94ef86fb8958ed89676ff9349b11d0 /net/wireless
parenta7022e65c68ad89d6eb64f21aa4831c3822403d4 (diff)
nl80211: support vendor-specific events
In addition to vendor-specific commands, also support vendor-specific events. These must be registered with cfg80211 before they can be used. They're also advertised in nl80211 in the wiphy information so that userspace knows can be expected. The events themselves are sent on a new multicast group called "vendor". Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/nl80211.c98
1 files changed, 79 insertions, 19 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 04681a46eda8..8a7ff041349b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -53,6 +53,7 @@ enum nl80211_multicast_groups {
53 NL80211_MCGRP_SCAN, 53 NL80211_MCGRP_SCAN,
54 NL80211_MCGRP_REGULATORY, 54 NL80211_MCGRP_REGULATORY,
55 NL80211_MCGRP_MLME, 55 NL80211_MCGRP_MLME,
56 NL80211_MCGRP_VENDOR,
56 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */ 57 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
57}; 58};
58 59
@@ -61,6 +62,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
61 [NL80211_MCGRP_SCAN] = { .name = "scan", }, 62 [NL80211_MCGRP_SCAN] = { .name = "scan", },
62 [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", }, 63 [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
63 [NL80211_MCGRP_MLME] = { .name = "mlme", }, 64 [NL80211_MCGRP_MLME] = { .name = "mlme", },
65 [NL80211_MCGRP_VENDOR] = { .name = "vendor", },
64#ifdef CONFIG_NL80211_TESTMODE 66#ifdef CONFIG_NL80211_TESTMODE
65 [NL80211_MCGRP_TESTMODE] = { .name = "testmode", } 67 [NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
66#endif 68#endif
@@ -1188,7 +1190,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1188 struct nlattr *nl_bands, *nl_band; 1190 struct nlattr *nl_bands, *nl_band;
1189 struct nlattr *nl_freqs, *nl_freq; 1191 struct nlattr *nl_freqs, *nl_freq;
1190 struct nlattr *nl_cmds; 1192 struct nlattr *nl_cmds;
1191 struct nlattr *nl_vendor_cmds;
1192 enum ieee80211_band band; 1193 enum ieee80211_band band;
1193 struct ieee80211_channel *chan; 1194 struct ieee80211_channel *chan;
1194 int i; 1195 int i;
@@ -1587,16 +1588,38 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
1587 state->split_start++; 1588 state->split_start++;
1588 break; 1589 break;
1589 case 11: 1590 case 11:
1590 nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); 1591 if (dev->wiphy.n_vendor_commands) {
1591 if (!nl_vendor_cmds) 1592 const struct nl80211_vendor_cmd_info *info;
1592 goto nla_put_failure; 1593 struct nlattr *nested;
1594
1595 nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
1596 if (!nested)
1597 goto nla_put_failure;
1598
1599 for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
1600 info = &dev->wiphy.vendor_commands[i].info;
1601 if (nla_put(msg, i + 1, sizeof(*info), info))
1602 goto nla_put_failure;
1603 }
1604 nla_nest_end(msg, nested);
1605 }
1606
1607 if (dev->wiphy.n_vendor_events) {
1608 const struct nl80211_vendor_cmd_info *info;
1609 struct nlattr *nested;
1593 1610
1594 for (i = 0; i < dev->wiphy.n_vendor_commands; i++) 1611 nested = nla_nest_start(msg,
1595 if (nla_put(msg, i + 1, 1612 NL80211_ATTR_VENDOR_EVENTS);
1596 sizeof(struct nl80211_vendor_cmd_info), 1613 if (!nested)
1597 &dev->wiphy.vendor_commands[i].info))
1598 goto nla_put_failure; 1614 goto nla_put_failure;
1599 nla_nest_end(msg, nl_vendor_cmds); 1615
1616 for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
1617 info = &dev->wiphy.vendor_events[i];
1618 if (nla_put(msg, i + 1, sizeof(*info), info))
1619 goto nla_put_failure;
1620 }
1621 nla_nest_end(msg, nested);
1622 }
1600 1623
1601 /* done */ 1624 /* done */
1602 state->split_start = 0; 1625 state->split_start = 0;
@@ -6726,7 +6749,9 @@ static struct sk_buff *
6726__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev, 6749__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
6727 int approxlen, u32 portid, u32 seq, 6750 int approxlen, u32 portid, u32 seq,
6728 enum nl80211_commands cmd, 6751 enum nl80211_commands cmd,
6729 enum nl80211_attrs attr, gfp_t gfp) 6752 enum nl80211_attrs attr,
6753 const struct nl80211_vendor_cmd_info *info,
6754 gfp_t gfp)
6730{ 6755{
6731 struct sk_buff *skb; 6756 struct sk_buff *skb;
6732 void *hdr; 6757 void *hdr;
@@ -6744,6 +6769,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
6744 6769
6745 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) 6770 if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
6746 goto nla_put_failure; 6771 goto nla_put_failure;
6772
6773 if (info) {
6774 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
6775 info->vendor_id))
6776 goto nla_put_failure;
6777 if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
6778 info->subcmd))
6779 goto nla_put_failure;
6780 }
6781
6747 data = nla_nest_start(skb, attr); 6782 data = nla_nest_start(skb, attr);
6748 6783
6749 ((void **)skb->cb)[0] = rdev; 6784 ((void **)skb->cb)[0] = rdev;
@@ -6884,29 +6919,54 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
6884 return err; 6919 return err;
6885} 6920}
6886 6921
6887struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, 6922struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
6888 int approxlen, gfp_t gfp) 6923 enum nl80211_commands cmd,
6924 enum nl80211_attrs attr,
6925 int vendor_event_idx,
6926 int approxlen, gfp_t gfp)
6889{ 6927{
6890 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 6928 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
6929 const struct nl80211_vendor_cmd_info *info;
6930
6931 switch (cmd) {
6932 case NL80211_CMD_TESTMODE:
6933 if (WARN_ON(vendor_event_idx != -1))
6934 return NULL;
6935 info = NULL;
6936 break;
6937 case NL80211_CMD_VENDOR:
6938 if (WARN_ON(vendor_event_idx < 0 ||
6939 vendor_event_idx >= wiphy->n_vendor_events))
6940 return NULL;
6941 info = &wiphy->vendor_events[vendor_event_idx];
6942 break;
6943 default:
6944 WARN_ON(1);
6945 return NULL;
6946 }
6891 6947
6892 return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0, 6948 return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
6893 NL80211_CMD_TESTMODE, 6949 cmd, attr, info, gfp);
6894 NL80211_ATTR_TESTDATA, gfp);
6895} 6950}
6896EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb); 6951EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
6897 6952
6898void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) 6953void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
6899{ 6954{
6900 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0]; 6955 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
6901 void *hdr = ((void **)skb->cb)[1]; 6956 void *hdr = ((void **)skb->cb)[1];
6902 struct nlattr *data = ((void **)skb->cb)[2]; 6957 struct nlattr *data = ((void **)skb->cb)[2];
6958 enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
6903 6959
6904 nla_nest_end(skb, data); 6960 nla_nest_end(skb, data);
6905 genlmsg_end(skb, hdr); 6961 genlmsg_end(skb, hdr);
6962
6963 if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
6964 mcgrp = NL80211_MCGRP_VENDOR;
6965
6906 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0, 6966 genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
6907 NL80211_MCGRP_TESTMODE, gfp); 6967 mcgrp, gfp);
6908} 6968}
6909EXPORT_SYMBOL(cfg80211_testmode_event); 6969EXPORT_SYMBOL(__cfg80211_send_event_skb);
6910#endif 6970#endif
6911 6971
6912static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) 6972static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
@@ -9039,7 +9099,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
9039 return __cfg80211_alloc_vendor_skb(rdev, approxlen, 9099 return __cfg80211_alloc_vendor_skb(rdev, approxlen,
9040 rdev->cur_cmd_info->snd_portid, 9100 rdev->cur_cmd_info->snd_portid,
9041 rdev->cur_cmd_info->snd_seq, 9101 rdev->cur_cmd_info->snd_seq,
9042 cmd, attr, GFP_KERNEL); 9102 cmd, attr, NULL, GFP_KERNEL);
9043} 9103}
9044EXPORT_SYMBOL(__cfg80211_alloc_reply_skb); 9104EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
9045 9105