diff options
-rw-r--r-- | include/linux/nl80211.h | 12 | ||||
-rw-r--r-- | include/net/cfg80211.h | 17 | ||||
-rw-r--r-- | net/wireless/mlme.c | 16 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 66 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 3 |
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, | |||
3193 | void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index, | 3195 | void 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 | */ | ||
3210 | bool 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 | ||
884 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) | 887 | void 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 | } |
1109 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); | 1112 | EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); |
1113 | |||
1114 | bool 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 | } | ||
1125 | EXPORT_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 | ||
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) |
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 | ||
120 | bool 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 */ |