diff options
author | Johannes Berg <johannes.berg@intel.com> | 2011-11-04 06:18:12 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-09 16:05:49 -0500 |
commit | 28946da763e8b8d8ffd01ab861b684a4afb4bc3b (patch) | |
tree | c4e1cd440702b81c2192a164356da4ba769a29a6 /net/wireless/nl80211.c | |
parent | 665c93a93e35cafcd8c84073824f1ef1b19f0a7d (diff) |
nl80211: allow subscribing to unexpected class3 frames
To implement AP mode without monitor interfaces we
need to be able to send a deauth to stations that
send frames without being associated. Enable this
by adding a new nl80211 event for such frames that
an application can subscribe to.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2bcaa579cebf..9910c3cb9a85 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -5832,6 +5832,23 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | |||
5832 | return err; | 5832 | return err; |
5833 | } | 5833 | } |
5834 | 5834 | ||
5835 | static int nl80211_register_unexpected_frame(struct sk_buff *skb, | ||
5836 | struct genl_info *info) | ||
5837 | { | ||
5838 | struct net_device *dev = info->user_ptr[1]; | ||
5839 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5840 | |||
5841 | if (wdev->iftype != NL80211_IFTYPE_AP && | ||
5842 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | ||
5843 | return -EINVAL; | ||
5844 | |||
5845 | if (wdev->ap_unexpected_nlpid) | ||
5846 | return -EBUSY; | ||
5847 | |||
5848 | wdev->ap_unexpected_nlpid = info->snd_pid; | ||
5849 | return 0; | ||
5850 | } | ||
5851 | |||
5835 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 5852 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
5836 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 5853 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
5837 | #define NL80211_FLAG_NEED_RTNL 0x04 | 5854 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -6387,6 +6404,14 @@ static struct genl_ops nl80211_ops[] = { | |||
6387 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 6404 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6388 | NL80211_FLAG_NEED_RTNL, | 6405 | NL80211_FLAG_NEED_RTNL, |
6389 | }, | 6406 | }, |
6407 | { | ||
6408 | .cmd = NL80211_CMD_UNEXPECTED_FRAME, | ||
6409 | .doit = nl80211_register_unexpected_frame, | ||
6410 | .policy = nl80211_policy, | ||
6411 | .flags = GENL_ADMIN_PERM, | ||
6412 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | ||
6413 | NL80211_FLAG_NEED_RTNL, | ||
6414 | }, | ||
6390 | }; | 6415 | }; |
6391 | 6416 | ||
6392 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6417 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -7171,6 +7196,47 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
7171 | nlmsg_free(msg); | 7196 | nlmsg_free(msg); |
7172 | } | 7197 | } |
7173 | 7198 | ||
7199 | bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp) | ||
7200 | { | ||
7201 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
7202 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
7203 | struct sk_buff *msg; | ||
7204 | void *hdr; | ||
7205 | int err; | ||
7206 | u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid); | ||
7207 | |||
7208 | if (!nlpid) | ||
7209 | return false; | ||
7210 | |||
7211 | msg = nlmsg_new(100, gfp); | ||
7212 | if (!msg) | ||
7213 | return true; | ||
7214 | |||
7215 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UNEXPECTED_FRAME); | ||
7216 | if (!hdr) { | ||
7217 | nlmsg_free(msg); | ||
7218 | return true; | ||
7219 | } | ||
7220 | |||
7221 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
7222 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
7223 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
7224 | |||
7225 | err = genlmsg_end(msg, hdr); | ||
7226 | if (err < 0) { | ||
7227 | nlmsg_free(msg); | ||
7228 | return true; | ||
7229 | } | ||
7230 | |||
7231 | genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid); | ||
7232 | return true; | ||
7233 | |||
7234 | nla_put_failure: | ||
7235 | genlmsg_cancel(msg, hdr); | ||
7236 | nlmsg_free(msg); | ||
7237 | return true; | ||
7238 | } | ||
7239 | |||
7174 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 7240 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
7175 | struct net_device *netdev, u32 nlpid, | 7241 | struct net_device *netdev, u32 nlpid, |
7176 | int freq, const u8 *buf, size_t len, gfp_t gfp) | 7242 | int freq, const u8 *buf, size_t len, gfp_t gfp) |