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>
This commit is contained in:
committed by
John W. Linville
parent
665c93a93e
commit
28946da763
@@ -509,6 +509,16 @@
|
|||||||
* @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
|
* @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
|
||||||
* @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
|
* @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
|
||||||
*
|
*
|
||||||
|
* @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
|
||||||
|
* (or GO) interface (i.e. hostapd) to ask for unexpected frames to
|
||||||
|
* implement sending deauth to stations that send unexpected class 3
|
||||||
|
* frames. Also used as the event sent by the kernel when such a frame
|
||||||
|
* is received.
|
||||||
|
* For the event, the %NL80211_ATTR_MAC attribute carries the TA and
|
||||||
|
* other attributes like the interface index are present.
|
||||||
|
* If used as the command it must have an interface index and you can
|
||||||
|
* only unsubscribe from the event by closing the socket.
|
||||||
|
*
|
||||||
* @NL80211_CMD_MAX: highest used command number
|
* @NL80211_CMD_MAX: highest used command number
|
||||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||||
*/
|
*/
|
||||||
@@ -638,6 +648,8 @@ enum nl80211_commands {
|
|||||||
NL80211_CMD_TDLS_OPER,
|
NL80211_CMD_TDLS_OPER,
|
||||||
NL80211_CMD_TDLS_MGMT,
|
NL80211_CMD_TDLS_MGMT,
|
||||||
|
|
||||||
|
NL80211_CMD_UNEXPECTED_FRAME,
|
||||||
|
|
||||||
/* add new commands above here */
|
/* add new commands above here */
|
||||||
|
|
||||||
/* used to define NL80211_CMD_MAX below */
|
/* used to define NL80211_CMD_MAX below */
|
||||||
|
@@ -2183,6 +2183,8 @@ struct wireless_dev {
|
|||||||
|
|
||||||
int beacon_interval;
|
int beacon_interval;
|
||||||
|
|
||||||
|
u32 ap_unexpected_nlpid;
|
||||||
|
|
||||||
#ifdef CONFIG_CFG80211_WEXT
|
#ifdef CONFIG_CFG80211_WEXT
|
||||||
/* wext data */
|
/* wext data */
|
||||||
struct {
|
struct {
|
||||||
@@ -3193,6 +3195,21 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
|
|||||||
void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
|
void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
|
||||||
const u8 *bssid, bool preauth, gfp_t gfp);
|
const u8 *bssid, bool preauth, gfp_t gfp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cfg80211_rx_spurious_frame - inform userspace about a spurious frame
|
||||||
|
* @dev: The device the frame matched to
|
||||||
|
* @addr: the transmitter address
|
||||||
|
* @gfp: context flags
|
||||||
|
*
|
||||||
|
* This function is used in AP mode (only!) to inform userspace that
|
||||||
|
* a spurious class 3 frame was received, to be able to deauth the
|
||||||
|
* sender.
|
||||||
|
* Returns %true if the frame was passed to userspace (or this failed
|
||||||
|
* for a reason other than not having a subscription.)
|
||||||
|
*/
|
||||||
|
bool cfg80211_rx_spurious_frame(struct net_device *dev,
|
||||||
|
const u8 *addr, gfp_t gfp);
|
||||||
|
|
||||||
/* Logging, debugging and troubleshooting/diagnostic helpers. */
|
/* Logging, debugging and troubleshooting/diagnostic helpers. */
|
||||||
|
|
||||||
/* wiphy_printk helpers, similar to dev_printk */
|
/* wiphy_printk helpers, similar to dev_printk */
|
||||||
|
@@ -879,6 +879,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
spin_unlock_bh(&wdev->mgmt_registrations_lock);
|
||||||
|
|
||||||
|
if (nlpid == wdev->ap_unexpected_nlpid)
|
||||||
|
wdev->ap_unexpected_nlpid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
|
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
|
||||||
@@ -1107,3 +1110,16 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
|
|||||||
nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
|
nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
|
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
|
||||||
|
|
||||||
|
bool cfg80211_rx_spurious_frame(struct net_device *dev,
|
||||||
|
const u8 *addr, gfp_t gfp)
|
||||||
|
{
|
||||||
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||||
|
|
||||||
|
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
|
||||||
|
wdev->iftype != NL80211_IFTYPE_P2P_GO))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return nl80211_unexpected_frame(dev, addr, gfp);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
|
||||||
|
@@ -5832,6 +5832,23 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
|
|||||||
return err;
|
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_WIPHY 0x01
|
||||||
#define NL80211_FLAG_NEED_NETDEV 0x02
|
#define NL80211_FLAG_NEED_NETDEV 0x02
|
||||||
#define NL80211_FLAG_NEED_RTNL 0x04
|
#define NL80211_FLAG_NEED_RTNL 0x04
|
||||||
@@ -6387,6 +6404,14 @@ static struct genl_ops nl80211_ops[] = {
|
|||||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||||
NL80211_FLAG_NEED_RTNL,
|
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 = {
|
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);
|
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,
|
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
|
||||||
struct net_device *netdev, u32 nlpid,
|
struct net_device *netdev, u32 nlpid,
|
||||||
int freq, const u8 *buf, size_t len, gfp_t gfp)
|
int freq, const u8 *buf, size_t len, gfp_t gfp)
|
||||||
|
@@ -117,4 +117,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
|
|||||||
struct net_device *netdev, int index,
|
struct net_device *netdev, int index,
|
||||||
const u8 *bssid, bool preauth, gfp_t gfp);
|
const u8 *bssid, bool preauth, gfp_t gfp);
|
||||||
|
|
||||||
|
bool nl80211_unexpected_frame(struct net_device *dev,
|
||||||
|
const u8 *addr, gfp_t gfp);
|
||||||
|
|
||||||
#endif /* __NET_WIRELESS_NL80211_H */
|
#endif /* __NET_WIRELESS_NL80211_H */
|
||||||
|
Reference in New Issue
Block a user