aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h12
-rw-r--r--include/net/cfg80211.h17
-rw-r--r--net/wireless/mlme.c16
-rw-r--r--net/wireless/nl80211.c66
-rw-r--r--net/wireless/nl80211.h3
5 files changed, 114 insertions, 0 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 8049bf77d799..9107adc73e0b 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -509,6 +509,16 @@
509 * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup). 509 * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
510 * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. 510 * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
511 * 511 *
512 * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
513 * (or GO) interface (i.e. hostapd) to ask for unexpected frames to
514 * implement sending deauth to stations that send unexpected class 3
515 * frames. Also used as the event sent by the kernel when such a frame
516 * is received.
517 * For the event, the %NL80211_ATTR_MAC attribute carries the TA and
518 * other attributes like the interface index are present.
519 * If used as the command it must have an interface index and you can
520 * only unsubscribe from the event by closing the socket.
521 *
512 * @NL80211_CMD_MAX: highest used command number 522 * @NL80211_CMD_MAX: highest used command number
513 * @__NL80211_CMD_AFTER_LAST: internal use 523 * @__NL80211_CMD_AFTER_LAST: internal use
514 */ 524 */
@@ -638,6 +648,8 @@ enum nl80211_commands {
638 NL80211_CMD_TDLS_OPER, 648 NL80211_CMD_TDLS_OPER,
639 NL80211_CMD_TDLS_MGMT, 649 NL80211_CMD_TDLS_MGMT,
640 650
651 NL80211_CMD_UNEXPECTED_FRAME,
652
641 /* add new commands above here */ 653 /* add new commands above here */
642 654
643 /* used to define NL80211_CMD_MAX below */ 655 /* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0c71d4a30cd6..ef118e452589 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2183,6 +2183,8 @@ struct wireless_dev {
2183 2183
2184 int beacon_interval; 2184 int beacon_interval;
2185 2185
2186 u32 ap_unexpected_nlpid;
2187
2186#ifdef CONFIG_CFG80211_WEXT 2188#ifdef CONFIG_CFG80211_WEXT
2187 /* wext data */ 2189 /* wext data */
2188 struct { 2190 struct {
@@ -3193,6 +3195,21 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
3193void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, 3195void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
3194 const u8 *bssid, bool preauth, gfp_t gfp); 3196 const u8 *bssid, bool preauth, gfp_t gfp);
3195 3197
3198/**
3199 * cfg80211_rx_spurious_frame - inform userspace about a spurious frame
3200 * @dev: The device the frame matched to
3201 * @addr: the transmitter address
3202 * @gfp: context flags
3203 *
3204 * This function is used in AP mode (only!) to inform userspace that
3205 * a spurious class 3 frame was received, to be able to deauth the
3206 * sender.
3207 * Returns %true if the frame was passed to userspace (or this failed
3208 * for a reason other than not having a subscription.)
3209 */
3210bool cfg80211_rx_spurious_frame(struct net_device *dev,
3211 const u8 *addr, gfp_t gfp);
3212
3196/* Logging, debugging and troubleshooting/diagnostic helpers. */ 3213/* Logging, debugging and troubleshooting/diagnostic helpers. */
3197 3214
3198/* wiphy_printk helpers, similar to dev_printk */ 3215/* wiphy_printk helpers, similar to dev_printk */
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 21fc9702f81c..f4d868b1e11c 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -879,6 +879,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
879 } 879 }
880 880
881 spin_unlock_bh(&wdev->mgmt_registrations_lock); 881 spin_unlock_bh(&wdev->mgmt_registrations_lock);
882
883 if (nlpid == wdev->ap_unexpected_nlpid)
884 wdev->ap_unexpected_nlpid = 0;
882} 885}
883 886
884void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) 887void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
@@ -1107,3 +1110,16 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
1107 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); 1110 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
1108} 1111}
1109EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); 1112EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
1113
1114bool cfg80211_rx_spurious_frame(struct net_device *dev,
1115 const u8 *addr, gfp_t gfp)
1116{
1117 struct wireless_dev *wdev = dev->ieee80211_ptr;
1118
1119 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
1120 wdev->iftype != NL80211_IFTYPE_P2P_GO))
1121 return false;
1122
1123 return nl80211_unexpected_frame(dev, addr, gfp);
1124}
1125EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
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
5835static 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
6392static struct genl_multicast_group nl80211_mlme_mcgrp = { 6417static 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
7199bool 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
7174int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, 7240int 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)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index f24a1fbeaf19..d94456e54f4e 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -117,4 +117,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
117 struct net_device *netdev, int index, 117 struct net_device *netdev, int index,
118 const u8 *bssid, bool preauth, gfp_t gfp); 118 const u8 *bssid, bool preauth, gfp_t gfp);
119 119
120bool nl80211_unexpected_frame(struct net_device *dev,
121 const u8 *addr, gfp_t gfp);
122
120#endif /* __NET_WIRELESS_NL80211_H */ 123#endif /* __NET_WIRELESS_NL80211_H */