Commit 6039f6d2 authored by Jouni Malinen's avatar Jouni Malinen Committed by John W. Linville

nl80211: Event notifications for MLME events

Add new nl80211 event notifications (and a new multicast group, "mlme")
for informing user space about received and processed Authentication,
(Re)Association Response, Deauthentication, and Disassociation frames in
station and IBSS modes (i.e., MLME SAP interface primitives
MLME-AUTHENTICATE.confirm, MLME-ASSOCIATE.confirm,
MLME-REASSOCIATE.confirm, MLME-DEAUTHENTICATE.indicate, and
MLME-DISASSOCIATE.indication). The event data is encapsulated as the 802.11
management frame since we already have the frame in that format and it
includes all the needed information.

This is the initial step in providing MLME SAP interface for
authentication and association with nl80211. In other words, kernel code
will act as the MLME and a user space application can control it as the
SME.
Signed-off-by: default avatarJouni Malinen <j@w1.fi>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a299542e
...@@ -161,6 +161,25 @@ ...@@ -161,6 +161,25 @@
* %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
* to (%NL80211_ATTR_REG_ALPHA2). * to (%NL80211_ATTR_REG_ALPHA2).
* *
* @NL80211_CMD_AUTHENTICATE: authentication notification (on the "mlme"
* multicast group). This event reports reception of an Authentication
* frame in station and IBSS modes when the local MLME processed the
* frame, i.e., it was for the local STA and was received in correct
* state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
* MLME SAP interface (kernel providing MLME, userspace SME). The
* included NL80211_ATTR_FRAME attribute contains the management frame
* (including both the header and frame body, but not FCS).
* @NL80211_CMD_ASSOCIATE: association notification; like
* NL80211_CMD_AUTHENTICATE but for Association Response and Reassociation
* Response frames (similar to MLME-ASSOCIATE.confirm or
* MLME-REASSOCIATE.confirm primitives).
* @NL80211_CMD_DEAUTHENTICATE: deauthentication notification; like
* NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
* MLME-DEAUTHENTICATE.indication primitive).
* @NL80211_CMD_DISASSOCIATE: disassociation notification; like
* NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
* MLME-DISASSOCIATE.indication primitive).
*
* @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
*/ */
...@@ -217,6 +236,11 @@ enum nl80211_commands { ...@@ -217,6 +236,11 @@ enum nl80211_commands {
NL80211_CMD_REG_CHANGE, NL80211_CMD_REG_CHANGE,
NL80211_CMD_AUTHENTICATE,
NL80211_CMD_ASSOCIATE,
NL80211_CMD_DEAUTHENTICATE,
NL80211_CMD_DISASSOCIATE,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* used to define NL80211_CMD_MAX below */
...@@ -230,8 +254,11 @@ enum nl80211_commands { ...@@ -230,8 +254,11 @@ enum nl80211_commands {
*/ */
#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE #define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE #define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
/** /**
* enum nl80211_attrs - nl80211 netlink attributes * enum nl80211_attrs - nl80211 netlink attributes
...@@ -353,6 +380,10 @@ enum nl80211_commands { ...@@ -353,6 +380,10 @@ enum nl80211_commands {
* an array of command numbers (i.e. a mapping index to command number) * an array of command numbers (i.e. a mapping index to command number)
* that the driver for the given wiphy supports. * that the driver for the given wiphy supports.
* *
* @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
* and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
* NL80211_CMD_ASSOCIATE events
*
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
*/ */
...@@ -432,6 +463,8 @@ enum nl80211_attrs { ...@@ -432,6 +463,8 @@ enum nl80211_attrs {
NL80211_ATTR_SUPPORTED_COMMANDS, NL80211_ATTR_SUPPORTED_COMMANDS,
NL80211_ATTR_FRAME,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
...@@ -451,6 +484,7 @@ enum nl80211_attrs { ...@@ -451,6 +484,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_IE NL80211_ATTR_IE #define NL80211_ATTR_IE NL80211_ATTR_IE
#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR #define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE #define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
#define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32 #define NL80211_MAX_SUPP_REG_RULES 32
......
...@@ -807,4 +807,50 @@ void cfg80211_put_bss(struct cfg80211_bss *bss); ...@@ -807,4 +807,50 @@ void cfg80211_put_bss(struct cfg80211_bss *bss);
*/ */
void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss); void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *bss);
/**
* cfg80211_send_rx_auth - notification of processed authentication
* @dev: network device
* @buf: authentication frame (header + body)
* @len: length of the frame data
*
* This function is called whenever an authentication has been processed in
* station mode.
*/
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
/**
* cfg80211_send_rx_assoc - notification of processed association
* @dev: network device
* @buf: (re)association response frame (header + body)
* @len: length of the frame data
*
* This function is called whenever a (re)association response has been
* processed in station mode.
*/
void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len);
/**
* cfg80211_send_rx_deauth - notification of processed deauthentication
* @dev: network device
* @buf: deauthentication frame (header + body)
* @len: length of the frame data
*
* This function is called whenever deauthentication has been processed in
* station mode.
*/
void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf,
size_t len);
/**
* cfg80211_send_rx_disassoc - notification of processed disassociation
* @dev: network device
* @buf: disassociation response frame (header + body)
* @len: length of the frame data
*
* This function is called whenever disassociation has been processed in
* station mode.
*/
void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf,
size_t len);
#endif /* __NET_CFG80211_H */ #endif /* __NET_CFG80211_H */
...@@ -1085,11 +1085,13 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, ...@@ -1085,11 +1085,13 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
case WLAN_AUTH_OPEN: case WLAN_AUTH_OPEN:
case WLAN_AUTH_LEAP: case WLAN_AUTH_LEAP:
ieee80211_auth_completed(sdata); ieee80211_auth_completed(sdata);
cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len);
break; break;
case WLAN_AUTH_SHARED_KEY: case WLAN_AUTH_SHARED_KEY:
if (ifmgd->auth_transaction == 4) if (ifmgd->auth_transaction == 4) {
ieee80211_auth_completed(sdata); ieee80211_auth_completed(sdata);
else cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len);
} else
ieee80211_auth_challenge(sdata, mgmt, len); ieee80211_auth_challenge(sdata, mgmt, len);
break; break;
} }
...@@ -1125,6 +1127,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, ...@@ -1125,6 +1127,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
ieee80211_set_disassoc(sdata, true, false, 0); ieee80211_set_disassoc(sdata, true, false, 0);
ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED;
cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len);
} }
...@@ -1154,6 +1157,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -1154,6 +1157,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
} }
ieee80211_set_disassoc(sdata, false, false, reason_code); ieee80211_set_disassoc(sdata, false, false, reason_code);
cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len);
} }
...@@ -1370,6 +1374,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ...@@ -1370,6 +1374,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_set_associated(sdata, changed); ieee80211_set_associated(sdata, changed);
ieee80211_associated(sdata); ieee80211_associated(sdata);
cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len);
} }
......
...@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o ...@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o
cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o
ccflags-y += -D__CHECK_ENDIAN__ ccflags-y += -D__CHECK_ENDIAN__
/*
* cfg80211 MLME SAP interface
*
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/nl80211.h>
#include <net/cfg80211.h>
#include "core.h"
#include "nl80211.h"
void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_rx_auth(rdev, dev, buf, len);
}
EXPORT_SYMBOL(cfg80211_send_rx_auth);
void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_rx_assoc(rdev, dev, buf, len);
}
EXPORT_SYMBOL(cfg80211_send_rx_assoc);
void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, size_t len)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_rx_deauth(rdev, dev, buf, len);
}
EXPORT_SYMBOL(cfg80211_send_rx_deauth);
void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf,
size_t len)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_rx_disassoc(rdev, dev, buf, len);
}
EXPORT_SYMBOL(cfg80211_send_rx_disassoc);
...@@ -2830,6 +2830,9 @@ static struct genl_ops nl80211_ops[] = { ...@@ -2830,6 +2830,9 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_scan, .dumpit = nl80211_dump_scan,
}, },
}; };
static struct genl_multicast_group nl80211_mlme_mcgrp = {
.name = "mlme",
};
/* multicast groups */ /* multicast groups */
static struct genl_multicast_group nl80211_config_mcgrp = { static struct genl_multicast_group nl80211_config_mcgrp = {
...@@ -2975,6 +2978,71 @@ nla_put_failure: ...@@ -2975,6 +2978,71 @@ nla_put_failure:
nlmsg_free(msg); nlmsg_free(msg);
} }
static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len,
enum nl80211_commands cmd)
{
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
if (!hdr) {
nlmsg_free(msg);
return;
}
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
if (genlmsg_end(msg, hdr) < 0) {
nlmsg_free(msg);
return;
}
genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
return;
nla_put_failure:
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf, size_t len)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_AUTHENTICATE);
}
void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
size_t len)
{
nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE);
}
void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
size_t len)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_DEAUTHENTICATE);
}
void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *buf,
size_t len)
{
nl80211_send_mlme_event(rdev, netdev, buf, len,
NL80211_CMD_DISASSOCIATE);
}
/* initialisation/exit functions */ /* initialisation/exit functions */
int nl80211_init(void) int nl80211_init(void)
...@@ -3003,6 +3071,10 @@ int nl80211_init(void) ...@@ -3003,6 +3071,10 @@ int nl80211_init(void)
if (err) if (err)
goto err_out; goto err_out;
err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp);
if (err)
goto err_out;
return 0; return 0;
err_out: err_out:
genl_unregister_family(&nl80211_fam); genl_unregister_family(&nl80211_fam);
......
...@@ -11,5 +11,17 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, ...@@ -11,5 +11,17 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
struct net_device *netdev); struct net_device *netdev);
extern void nl80211_send_reg_change_event(struct regulatory_request *request); extern void nl80211_send_reg_change_event(struct regulatory_request *request);
extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len);
extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len);
extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len);
extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len);
#endif /* __NET_WIRELESS_NL80211_H */ #endif /* __NET_WIRELESS_NL80211_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment