Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Jouni 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: Johannes Berg <johannes.berg@intel.com>

authored by

Jouni Malinen and committed by
Johannes Berg
bf1ecd21 0bb7ed42

+58 -24
+1
Documentation/DocBook/80211.tmpl
··· 136 136 !Finclude/net/cfg80211.h cfg80211_ibss_joined 137 137 !Finclude/net/cfg80211.h cfg80211_connect_result 138 138 !Finclude/net/cfg80211.h cfg80211_connect_bss 139 + !Finclude/net/cfg80211.h cfg80211_connect_timeout 139 140 !Finclude/net/cfg80211.h cfg80211_roamed 140 141 !Finclude/net/cfg80211.h cfg80211_disconnected 141 142 !Finclude/net/cfg80211.h cfg80211_ready_on_channel
+40 -13
include/net/cfg80211.h
··· 2367 2367 * (invoked with the wireless_dev mutex held) 2368 2368 * 2369 2369 * @connect: Connect to the ESS with the specified parameters. When connected, 2370 - * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. 2371 - * If the connection fails for some reason, call cfg80211_connect_result() 2372 - * with the status from the AP. The driver is allowed to roam to other 2373 - * BSSes within the ESS when the other BSS matches the connect parameters. 2374 - * When such roaming is initiated by the driver, the driver is expected to 2375 - * verify that the target matches the configured security parameters and 2376 - * to use Reassociation Request frame instead of Association Request frame. 2377 - * The connect function can also be used to request the driver to perform 2378 - * a specific roam when connected to an ESS. In that case, the prev_bssid 2370 + * call cfg80211_connect_result()/cfg80211_connect_bss() with status code 2371 + * %WLAN_STATUS_SUCCESS. If the connection fails for some reason, call 2372 + * cfg80211_connect_result()/cfg80211_connect_bss() with the status code 2373 + * from the AP or cfg80211_connect_timeout() if no frame with status code 2374 + * was received. 2375 + * The driver is allowed to roam to other BSSes within the ESS when the 2376 + * other BSS matches the connect parameters. When such roaming is initiated 2377 + * by the driver, the driver is expected to verify that the target matches 2378 + * the configured security parameters and to use Reassociation Request 2379 + * frame instead of Association Request frame. 2380 + * The connect function can also be used to request the driver to perform a 2381 + * specific roam when connected to an ESS. In that case, the prev_bssid 2379 2382 * parameter is set to the BSSID of the currently associated BSS as an 2380 - * indication of requesting reassociation. In both the driver-initiated and 2381 - * new connect() call initiated roaming cases, the result of roaming is 2382 - * indicated with a call to cfg80211_roamed() or cfg80211_roamed_bss(). 2383 + * indication of requesting reassociation. 2384 + * In both the driver-initiated and new connect() call initiated roaming 2385 + * cases, the result of roaming is indicated with a call to 2386 + * cfg80211_roamed() or cfg80211_roamed_bss(). 2383 2387 * (invoked with the wireless_dev mutex held) 2384 2388 * @disconnect: Disconnect from the BSS/ESS. 2385 2389 * (invoked with the wireless_dev mutex held) ··· 4684 4680 void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, 4685 4681 struct cfg80211_bss *bss, const u8 *req_ie, 4686 4682 size_t req_ie_len, const u8 *resp_ie, 4687 - size_t resp_ie_len, u16 status, gfp_t gfp); 4683 + size_t resp_ie_len, int status, gfp_t gfp); 4688 4684 4689 4685 /** 4690 4686 * cfg80211_connect_result - notify cfg80211 of connection result ··· 4711 4707 { 4712 4708 cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie, 4713 4709 resp_ie_len, status, gfp); 4710 + } 4711 + 4712 + /** 4713 + * cfg80211_connect_timeout - notify cfg80211 of connection timeout 4714 + * 4715 + * @dev: network device 4716 + * @bssid: the BSSID of the AP 4717 + * @req_ie: association request IEs (maybe be %NULL) 4718 + * @req_ie_len: association request IEs length 4719 + * @gfp: allocation flags 4720 + * 4721 + * It should be called by the underlying driver whenever connect() has failed 4722 + * in a sequence where no explicit authentication/association rejection was 4723 + * received from the AP. This could happen, e.g., due to not being able to send 4724 + * out the Authentication or Association Request frame or timing out while 4725 + * waiting for the response. 4726 + */ 4727 + static inline void 4728 + cfg80211_connect_timeout(struct net_device *dev, const u8 *bssid, 4729 + const u8 *req_ie, size_t req_ie_len, gfp_t gfp) 4730 + { 4731 + cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, NULL, 0, -1, 4732 + gfp); 4714 4733 } 4715 4734 4716 4735 /**
+6 -1
include/uapi/linux/nl80211.h
··· 493 493 * This attribute is ignored if driver does not support roam scan. 494 494 * It is also sent as an event, with the BSSID and response IEs when the 495 495 * connection is established or failed to be established. This can be 496 - * determined by the STATUS_CODE attribute. 496 + * determined by the %NL80211_ATTR_STATUS_CODE attribute (0 = success, 497 + * non-zero = failure). If %NL80211_ATTR_TIMED_OUT is included in the 498 + * event, the connection attempt failed due to not being able to initiate 499 + * authentication/association or not receiving a response from the AP. 500 + * Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as 501 + * well to remain backwards compatible. 497 502 * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), 498 503 * sent as an event when the card/driver roamed by itself. 499 504 * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+2 -2
net/wireless/core.h
··· 214 214 size_t req_ie_len; 215 215 size_t resp_ie_len; 216 216 struct cfg80211_bss *bss; 217 - u16 status; 217 + int status; /* -1 = failed; 0..65535 = status code */ 218 218 } cr; 219 219 struct { 220 220 const u8 *req_ie; ··· 374 374 void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 375 375 const u8 *req_ie, size_t req_ie_len, 376 376 const u8 *resp_ie, size_t resp_ie_len, 377 - u16 status, bool wextev, 377 + int status, bool wextev, 378 378 struct cfg80211_bss *bss); 379 379 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, 380 380 size_t ie_len, u16 reason, bool from_ap);
+5 -2
net/wireless/nl80211.c
··· 12092 12092 struct net_device *netdev, const u8 *bssid, 12093 12093 const u8 *req_ie, size_t req_ie_len, 12094 12094 const u8 *resp_ie, size_t resp_ie_len, 12095 - u16 status, gfp_t gfp) 12095 + int status, gfp_t gfp) 12096 12096 { 12097 12097 struct sk_buff *msg; 12098 12098 void *hdr; ··· 12110 12110 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || 12111 12111 nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || 12112 12112 (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid)) || 12113 - nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status) || 12113 + nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, 12114 + status < 0 ? WLAN_STATUS_UNSPECIFIED_FAILURE : 12115 + status) || 12116 + (status < 0 && nla_put_flag(msg, NL80211_ATTR_TIMED_OUT)) || 12114 12117 (req_ie && 12115 12118 nla_put(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie)) || 12116 12119 (resp_ie &&
+1 -1
net/wireless/nl80211.h
··· 55 55 struct net_device *netdev, const u8 *bssid, 56 56 const u8 *req_ie, size_t req_ie_len, 57 57 const u8 *resp_ie, size_t resp_ie_len, 58 - u16 status, gfp_t gfp); 58 + int status, gfp_t gfp); 59 59 void nl80211_send_roamed(struct cfg80211_registered_device *rdev, 60 60 struct net_device *netdev, const u8 *bssid, 61 61 const u8 *req_ie, size_t req_ie_len,
+3 -5
net/wireless/sme.c
··· 244 244 if (cfg80211_conn_do_work(wdev)) { 245 245 __cfg80211_connect_result( 246 246 wdev->netdev, bssid, 247 - NULL, 0, NULL, 0, 248 - WLAN_STATUS_UNSPECIFIED_FAILURE, 249 - false, NULL); 247 + NULL, 0, NULL, 0, -1, false, NULL); 250 248 } 251 249 wdev_unlock(wdev); 252 250 } ··· 646 648 void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 647 649 const u8 *req_ie, size_t req_ie_len, 648 650 const u8 *resp_ie, size_t resp_ie_len, 649 - u16 status, bool wextev, 651 + int status, bool wextev, 650 652 struct cfg80211_bss *bss) 651 653 { 652 654 struct wireless_dev *wdev = dev->ieee80211_ptr; ··· 755 757 void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, 756 758 struct cfg80211_bss *bss, const u8 *req_ie, 757 759 size_t req_ie_len, const u8 *resp_ie, 758 - size_t resp_ie_len, u16 status, gfp_t gfp) 760 + size_t resp_ie_len, int status, gfp_t gfp) 759 761 { 760 762 struct wireless_dev *wdev = dev->ieee80211_ptr; 761 763 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);