|
@@ -5832,6 +5832,23 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int nl80211_register_unexpected_frame(struct sk_buff *skb,
|
|
|
+ struct genl_info *info)
|
|
|
+{
|
|
|
+ struct net_device *dev = info->user_ptr[1];
|
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
+
|
|
|
+ if (wdev->iftype != NL80211_IFTYPE_AP &&
|
|
|
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (wdev->ap_unexpected_nlpid)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ wdev->ap_unexpected_nlpid = info->snd_pid;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
#define NL80211_FLAG_NEED_WIPHY 0x01
|
|
|
#define NL80211_FLAG_NEED_NETDEV 0x02
|
|
|
#define NL80211_FLAG_NEED_RTNL 0x04
|
|
@@ -6387,6 +6404,14 @@ static struct genl_ops nl80211_ops[] = {
|
|
|
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
|
|
NL80211_FLAG_NEED_RTNL,
|
|
|
},
|
|
|
+ {
|
|
|
+ .cmd = NL80211_CMD_UNEXPECTED_FRAME,
|
|
|
+ .doit = nl80211_register_unexpected_frame,
|
|
|
+ .policy = nl80211_policy,
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
|
@@ -7171,6 +7196,47 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
|
|
|
nlmsg_free(msg);
|
|
|
}
|
|
|
|
|
|
+bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
|
|
|
+{
|
|
|
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
|
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
|
|
+ struct sk_buff *msg;
|
|
|
+ void *hdr;
|
|
|
+ int err;
|
|
|
+ u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid);
|
|
|
+
|
|
|
+ if (!nlpid)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ msg = nlmsg_new(100, gfp);
|
|
|
+ if (!msg)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UNEXPECTED_FRAME);
|
|
|
+ if (!hdr) {
|
|
|
+ nlmsg_free(msg);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
|
|
|
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
|
|
|
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
|
|
|
+
|
|
|
+ err = genlmsg_end(msg, hdr);
|
|
|
+ if (err < 0) {
|
|
|
+ nlmsg_free(msg);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
|
|
|
+ return true;
|
|
|
+
|
|
|
+ nla_put_failure:
|
|
|
+ genlmsg_cancel(msg, hdr);
|
|
|
+ nlmsg_free(msg);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
|
|
|
struct net_device *netdev, u32 nlpid,
|
|
|
int freq, const u8 *buf, size_t len, gfp_t gfp)
|