Commit bf1ecd21 authored by Jouni Malinen's avatar Jouni Malinen Committed by Johannes Berg

cfg80211: Allow cfg80211_connect_result() errors to be distinguished

Previously, the status parameter to cfg80211_connect_result() was
documented as using WLAN_STATUS_UNSPECIFIED_FAILURE (1) when the real
status code for the failure is not known. This value can be used by an
AP (and often is) and as such, user space cannot distinguish between
explicitly rejected authentication/association and not being able to
even try to associate or not receiving a response from the AP.

Add a new inline function, cfg80211_connect_timeout(), to be used when
the driver knows that the connection attempt failed due to a reason
where connection could not be attempt or no response was received from
the AP. The internal functions now allow a negative status value (-1) to
be used as an indication of this special case. This results in the
NL80211_ATTR_TIMED_OUT to be added to the NL80211_CMD_CONNECT event to
allow user space to determine this case was hit. For backwards
compatibility, NL80211_STATUS_CODE with the value
WLAN_STATUS_UNSPECIFIED_FAILURE is still indicated in the event in such
a case.
Signed-off-by: default avatarJouni Malinen <jouni@qca.qualcomm.com>
[johannes: fix cfg80211_connect_bss() prototype to use int for status,
 add cfg80211_connect_timeout() to docbook, fix docbook]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 0bb7ed42
...@@ -136,6 +136,7 @@ ...@@ -136,6 +136,7 @@
!Finclude/net/cfg80211.h cfg80211_ibss_joined !Finclude/net/cfg80211.h cfg80211_ibss_joined
!Finclude/net/cfg80211.h cfg80211_connect_result !Finclude/net/cfg80211.h cfg80211_connect_result
!Finclude/net/cfg80211.h cfg80211_connect_bss !Finclude/net/cfg80211.h cfg80211_connect_bss
!Finclude/net/cfg80211.h cfg80211_connect_timeout
!Finclude/net/cfg80211.h cfg80211_roamed !Finclude/net/cfg80211.h cfg80211_roamed
!Finclude/net/cfg80211.h cfg80211_disconnected !Finclude/net/cfg80211.h cfg80211_disconnected
!Finclude/net/cfg80211.h cfg80211_ready_on_channel !Finclude/net/cfg80211.h cfg80211_ready_on_channel
......
...@@ -2367,19 +2367,23 @@ struct cfg80211_qos_map { ...@@ -2367,19 +2367,23 @@ struct cfg80211_qos_map {
* (invoked with the wireless_dev mutex held) * (invoked with the wireless_dev mutex held)
* *
* @connect: Connect to the ESS with the specified parameters. When connected, * @connect: Connect to the ESS with the specified parameters. When connected,
* call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. * call cfg80211_connect_result()/cfg80211_connect_bss() with status code
* If the connection fails for some reason, call cfg80211_connect_result() * %WLAN_STATUS_SUCCESS. If the connection fails for some reason, call
* with the status from the AP. The driver is allowed to roam to other * cfg80211_connect_result()/cfg80211_connect_bss() with the status code
* BSSes within the ESS when the other BSS matches the connect parameters. * from the AP or cfg80211_connect_timeout() if no frame with status code
* When such roaming is initiated by the driver, the driver is expected to * was received.
* verify that the target matches the configured security parameters and * The driver is allowed to roam to other BSSes within the ESS when the
* to use Reassociation Request frame instead of Association Request frame. * other BSS matches the connect parameters. When such roaming is initiated
* The connect function can also be used to request the driver to perform * by the driver, the driver is expected to verify that the target matches
* a specific roam when connected to an ESS. In that case, the prev_bssid * the configured security parameters and to use Reassociation Request
* frame instead of Association Request frame.
* The connect function can also be used to request the driver to perform a
* specific roam when connected to an ESS. In that case, the prev_bssid
* parameter is set to the BSSID of the currently associated BSS as an * parameter is set to the BSSID of the currently associated BSS as an
* indication of requesting reassociation. In both the driver-initiated and * indication of requesting reassociation.
* new connect() call initiated roaming cases, the result of roaming is * In both the driver-initiated and new connect() call initiated roaming
* indicated with a call to cfg80211_roamed() or cfg80211_roamed_bss(). * cases, the result of roaming is indicated with a call to
* cfg80211_roamed() or cfg80211_roamed_bss().
* (invoked with the wireless_dev mutex held) * (invoked with the wireless_dev mutex held)
* @disconnect: Disconnect from the BSS/ESS. * @disconnect: Disconnect from the BSS/ESS.
* (invoked with the wireless_dev mutex held) * (invoked with the wireless_dev mutex held)
...@@ -4680,7 +4684,7 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) ...@@ -4680,7 +4684,7 @@ static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
struct cfg80211_bss *bss, const u8 *req_ie, struct cfg80211_bss *bss, const u8 *req_ie,
size_t req_ie_len, const u8 *resp_ie, size_t req_ie_len, const u8 *resp_ie,
size_t resp_ie_len, u16 status, gfp_t gfp); size_t resp_ie_len, int status, gfp_t gfp);
/** /**
* cfg80211_connect_result - notify cfg80211 of connection result * cfg80211_connect_result - notify cfg80211 of connection result
...@@ -4709,6 +4713,29 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid, ...@@ -4709,6 +4713,29 @@ cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
resp_ie_len, status, gfp); resp_ie_len, status, gfp);
} }
/**
* cfg80211_connect_timeout - notify cfg80211 of connection timeout
*
* @dev: network device
* @bssid: the BSSID of the AP
* @req_ie: association request IEs (maybe be %NULL)
* @req_ie_len: association request IEs length
* @gfp: allocation flags
*
* It should be called by the underlying driver whenever connect() has failed
* in a sequence where no explicit authentication/association rejection was
* received from the AP. This could happen, e.g., due to not being able to send
* out the Authentication or Association Request frame or timing out while
* waiting for the response.
*/
static inline void
cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len, gfp_t gfp)
{
cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, NULL, 0, -1,
gfp);
}
/** /**
* cfg80211_roamed - notify cfg80211 of roaming * cfg80211_roamed - notify cfg80211 of roaming
* *
......
...@@ -493,7 +493,12 @@ ...@@ -493,7 +493,12 @@
* This attribute is ignored if driver does not support roam scan. * This attribute is ignored if driver does not support roam scan.
* It is also sent as an event, with the BSSID and response IEs when the * It is also sent as an event, with the BSSID and response IEs when the
* connection is established or failed to be established. This can be * connection is established or failed to be established. This can be
* determined by the STATUS_CODE attribute. * determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success,
* non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the
* event, the connection attempt failed due to not being able to initiate
* authentication/association or not receiving a response from the AP.
* Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as
* well to remain backwards compatible.
* @NL80211_CMD_ROAM: request that the card roam (currently not implemented), * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
* sent as an event when the card/driver roamed by itself. * sent as an event when the card/driver roamed by itself.
* @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
......
...@@ -214,7 +214,7 @@ struct cfg80211_event { ...@@ -214,7 +214,7 @@ struct cfg80211_event {
size_t req_ie_len; size_t req_ie_len;
size_t resp_ie_len; size_t resp_ie_len;
struct cfg80211_bss *bss; struct cfg80211_bss *bss;
u16 status; int status; /* -1 = failed; 0..65535 = status code */
} cr; } cr;
struct { struct {
const u8 *req_ie; const u8 *req_ie;
...@@ -374,7 +374,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, ...@@ -374,7 +374,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len, const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len, const u8 *resp_ie, size_t resp_ie_len,
u16 status, bool wextev, int status, bool wextev,
struct cfg80211_bss *bss); struct cfg80211_bss *bss);
void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
size_t ie_len, u16 reason, bool from_ap); size_t ie_len, u16 reason, bool from_ap);
......
...@@ -12092,7 +12092,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, ...@@ -12092,7 +12092,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid, struct net_device *netdev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len, const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len, const u8 *resp_ie, size_t resp_ie_len,
u16 status, gfp_t gfp) int status, gfp_t gfp)
{ {
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
...@@ -12110,7 +12110,10 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, ...@@ -12110,7 +12110,10 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
(bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) || (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) ||
nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status) || nla_put_u16(msg, NL80211_ATTR_STATUS_CODE,
status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE :
status) ||
(status < 0 && nla_put_flag(msg, NL80211_ATTR_TIMED_OUT)) ||
(req_ie && (req_ie &&
nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) || nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) ||
(resp_ie && (resp_ie &&
......
...@@ -55,7 +55,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, ...@@ -55,7 +55,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid, struct net_device *netdev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len, const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len, const u8 *resp_ie, size_t resp_ie_len,
u16 status, gfp_t gfp); int status, gfp_t gfp);
void nl80211_send_roamed(struct cfg80211_registered_device *rdev, void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid, struct net_device *netdev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len, const u8 *req_ie, size_t req_ie_len,
......
...@@ -244,9 +244,7 @@ void cfg80211_conn_work(struct work_struct *work) ...@@ -244,9 +244,7 @@ void cfg80211_conn_work(struct work_struct *work)
if (cfg80211_conn_do_work(wdev)) { if (cfg80211_conn_do_work(wdev)) {
__cfg80211_connect_result( __cfg80211_connect_result(
wdev->netdev, bssid, wdev->netdev, bssid,
NULL, 0, NULL, 0, NULL, 0, NULL, 0, -1, false, NULL);
WLAN_STATUS_UNSPECIFIED_FAILURE,
false, NULL);
} }
wdev_unlock(wdev); wdev_unlock(wdev);
} }
...@@ -648,7 +646,7 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); ...@@ -648,7 +646,7 @@ static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
const u8 *req_ie, size_t req_ie_len, const u8 *req_ie, size_t req_ie_len,
const u8 *resp_ie, size_t resp_ie_len, const u8 *resp_ie, size_t resp_ie_len,
u16 status, bool wextev, int status, bool wextev,
struct cfg80211_bss *bss) struct cfg80211_bss *bss)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
...@@ -757,7 +755,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, ...@@ -757,7 +755,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid,
struct cfg80211_bss *bss, const u8 *req_ie, struct cfg80211_bss *bss, const u8 *req_ie,
size_t req_ie_len, const u8 *resp_ie, size_t req_ie_len, const u8 *resp_ie,
size_t resp_ie_len, u16 status, gfp_t gfp) size_t resp_ie_len, int status, gfp_t gfp)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
......
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