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

cfg80211: Add option to report the bss entry in connect result

Since cfg80211 maintains separate BSS table entries for APs if the same
BSSID, SSID pair is seen on multiple channels, it is possible that it
can map the current_bss to a BSS entry on the wrong channel. This
current_bss will not get flushed unless disconnected and cfg80211
reports a wrong channel as the associated channel.

Fix this by introducing a new cfg80211_connect_bss() function which is
similar to cfg80211_connect_result(), but it includes an additional
parameter: the bss the STA is connected to. This allows drivers to
provide the exact bss entry that matches the BSS to which the connection
was completed.

Reviewed-by: Jouni Malinen <jouni@qca.qualcomm.com>
Signed-off-by: Vidyullatha Kanchanapally <vkanchan@qti.qualcomm.com>
Signed-off-by: Sunil Dutt <usdutt@qti.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Kanchanapally, Vidyullatha and committed by
Johannes Berg
e7054989 739960f1

+60 -11
+1
Documentation/DocBook/80211.tmpl
··· 135 135 !Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt 136 136 !Finclude/net/cfg80211.h cfg80211_ibss_joined 137 137 !Finclude/net/cfg80211.h cfg80211_connect_result 138 + !Finclude/net/cfg80211.h cfg80211_connect_bss 138 139 !Finclude/net/cfg80211.h cfg80211_roamed 139 140 !Finclude/net/cfg80211.h cfg80211_disconnected 140 141 !Finclude/net/cfg80211.h cfg80211_ready_on_channel
+35 -4
include/net/cfg80211.h
··· 4652 4652 #endif 4653 4653 4654 4654 /** 4655 + * cfg80211_connect_bss - notify cfg80211 of connection result 4656 + * 4657 + * @dev: network device 4658 + * @bssid: the BSSID of the AP 4659 + * @bss: entry of bss to which STA got connected to, can be obtained 4660 + * through cfg80211_get_bss (may be %NULL) 4661 + * @req_ie: association request IEs (maybe be %NULL) 4662 + * @req_ie_len: association request IEs length 4663 + * @resp_ie: association response IEs (may be %NULL) 4664 + * @resp_ie_len: assoc response IEs length 4665 + * @status: status code, 0 for successful connection, use 4666 + * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you 4667 + * the real status code for failures. 4668 + * @gfp: allocation flags 4669 + * 4670 + * It should be called by the underlying driver whenever connect() has 4671 + * succeeded. This is similar to cfg80211_connect_result(), but with the 4672 + * option of identifying the exact bss entry for the connection. Only one of 4673 + * these functions should be called. 4674 + */ 4675 + void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, 4676 + struct cfg80211_bss *bss, const u8 *req_ie, 4677 + size_t req_ie_len, const u8 *resp_ie, 4678 + size_t resp_ie_len, u16 status, gfp_t gfp); 4679 + 4680 + /** 4655 4681 * cfg80211_connect_result - notify cfg80211 of connection result 4656 4682 * 4657 4683 * @dev: network device ··· 4694 4668 * It should be called by the underlying driver whenever connect() has 4695 4669 * succeeded. 4696 4670 */ 4697 - void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 4698 - const u8 *req_ie, size_t req_ie_len, 4699 - const u8 *resp_ie, size_t resp_ie_len, 4700 - u16 status, gfp_t gfp); 4671 + static inline void 4672 + cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 4673 + const u8 *req_ie, size_t req_ie_len, 4674 + const u8 *resp_ie, size_t resp_ie_len, 4675 + u16 status, gfp_t gfp) 4676 + { 4677 + cfg80211_connect_bss(dev, bssid, NULL, req_ie, req_ie_len, resp_ie, 4678 + resp_ie_len, status, gfp); 4679 + } 4701 4680 4702 4681 /** 4703 4682 * cfg80211_roamed - notify cfg80211 of roaming
+1
net/wireless/core.h
··· 214 214 const u8 *resp_ie; 215 215 size_t req_ie_len; 216 216 size_t resp_ie_len; 217 + struct cfg80211_bss *bss; 217 218 u16 status; 218 219 } cr; 219 220 struct {
+22 -6
net/wireless/sme.c
··· 753 753 kfree(country_ie); 754 754 } 755 755 756 - void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 757 - const u8 *req_ie, size_t req_ie_len, 758 - const u8 *resp_ie, size_t resp_ie_len, 759 - u16 status, gfp_t gfp) 756 + /* Consumes bss object one way or another */ 757 + void cfg80211_connect_bss(struct net_device *dev, const u8 *bssid, 758 + struct cfg80211_bss *bss, const u8 *req_ie, 759 + size_t req_ie_len, const u8 *resp_ie, 760 + size_t resp_ie_len, u16 status, gfp_t gfp) 760 761 { 761 762 struct wireless_dev *wdev = dev->ieee80211_ptr; 762 763 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 763 764 struct cfg80211_event *ev; 764 765 unsigned long flags; 765 766 767 + if (bss) { 768 + /* Make sure the bss entry provided by the driver is valid. */ 769 + struct cfg80211_internal_bss *ibss = bss_from_pub(bss); 770 + 771 + if (WARN_ON(list_empty(&ibss->list))) { 772 + cfg80211_put_bss(wdev->wiphy, bss); 773 + return; 774 + } 775 + } 776 + 766 777 ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); 767 - if (!ev) 778 + if (!ev) { 779 + cfg80211_put_bss(wdev->wiphy, bss); 768 780 return; 781 + } 769 782 770 783 ev->type = EVENT_CONNECT_RESULT; 771 784 if (bssid) ··· 793 780 ev->cr.resp_ie_len = resp_ie_len; 794 781 memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); 795 782 } 783 + if (bss) 784 + cfg80211_hold_bss(bss_from_pub(bss)); 785 + ev->cr.bss = bss; 796 786 ev->cr.status = status; 797 787 798 788 spin_lock_irqsave(&wdev->event_lock, flags); ··· 803 787 spin_unlock_irqrestore(&wdev->event_lock, flags); 804 788 queue_work(cfg80211_wq, &rdev->event_work); 805 789 } 806 - EXPORT_SYMBOL(cfg80211_connect_result); 790 + EXPORT_SYMBOL(cfg80211_connect_bss); 807 791 808 792 /* Consumes bss object one way or another */ 809 793 void __cfg80211_roamed(struct wireless_dev *wdev,
+1 -1
net/wireless/util.c
··· 950 950 ev->cr.resp_ie, ev->cr.resp_ie_len, 951 951 ev->cr.status, 952 952 ev->cr.status == WLAN_STATUS_SUCCESS, 953 - NULL); 953 + ev->cr.bss); 954 954 break; 955 955 case EVENT_ROAMED: 956 956 __cfg80211_roamed(wdev, ev->rm.bss, ev->rm.req_ie,