aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2012-09-11 15:18:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-09-12 14:19:16 -0400
commite756af5b30b008f6ffcfebf8ad0b477f6f225b62 (patch)
treebb5da7c5310e4209e38152219adeb9ff8d7d6a75
parentd74a0b514de6996021573e5406af8d06da188794 (diff)
brcmfmac: add e-scan support.
This patch adds e-scan support (currently i-scan is in use). E-scan is a more powerful and memory efficient method for scanning. E-scan will be the default scan method and eventually, i-scan support will be removed. The scan methods do not make any difference to the end-user. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/Kconfig8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h22
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c522
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h25
5 files changed, 583 insertions, 2 deletions
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig
index b480088b3dbe..c9d811eb6556 100644
--- a/drivers/net/wireless/brcm80211/Kconfig
+++ b/drivers/net/wireless/brcm80211/Kconfig
@@ -55,6 +55,14 @@ config BRCMFMAC_USB
55 IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to 55 IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
56 use the driver for an USB wireless card. 56 use the driver for an USB wireless card.
57 57
58config BRCMISCAN
59 bool "Broadcom I-Scan (OBSOLETE)"
60 depends on BRCMFMAC
61 ---help---
62 This option enables the I-Scan method. By default fullmac uses the
63 new E-Scan method which uses less memory in firmware and gives no
64 limitation on the number of scan results.
65
58config BRCMDBG 66config BRCMDBG
59 bool "Broadcom driver debug functions" 67 bool "Broadcom driver debug functions"
60 depends on BRCMSMAC || BRCMFMAC 68 depends on BRCMSMAC || BRCMFMAC
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 9e2fb5bc932f..4766d9f35696 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -130,6 +130,10 @@
130#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 130#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
131#define BRCMF_EVENT_MSG_GROUP 0x04 131#define BRCMF_EVENT_MSG_GROUP 0x04
132 132
133#define BRCMF_ESCAN_REQ_VERSION 1
134
135#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
136
133struct brcmf_event_msg { 137struct brcmf_event_msg {
134 __be16 version; 138 __be16 version;
135 __be16 flags; 139 __be16 flags;
@@ -456,6 +460,24 @@ struct brcmf_scan_results_le {
456 __le32 count; 460 __le32 count;
457}; 461};
458 462
463struct brcmf_escan_params_le {
464 __le32 version;
465 __le16 action;
466 __le16 sync_id;
467 struct brcmf_scan_params_le params_le;
468};
469
470struct brcmf_escan_result_le {
471 __le32 buflen;
472 __le32 version;
473 __le16 sync_id;
474 __le16 bss_count;
475 struct brcmf_bss_info_le bss_info_le;
476};
477
478#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \
479 sizeof(struct brcmf_bss_info_le))
480
459/* used for association with a specific BSSID and chanspec list */ 481/* used for association with a specific BSSID and chanspec list */
460struct brcmf_assoc_params_le { 482struct brcmf_assoc_params_le {
461 /* 00:00:00:00:00:00: broadcast scan */ 483 /* 00:00:00:00:00:00: broadcast scan */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
index 2621dd3d7dcd..f6b862d77986 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
@@ -205,7 +205,8 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
205 BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, { 205 BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
206 BRCMF_E_IF, "IF"}, { 206 BRCMF_E_IF, "IF"}, {
207 BRCMF_E_RSSI, "RSSI"}, { 207 BRCMF_E_RSSI, "RSSI"}, {
208 BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"} 208 BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
209 BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT"}
209 }; 210 };
210 uint event_type, flags, auth_type, datalen; 211 uint event_type, flags, auth_type, datalen;
211 static u32 seqnum_prev; 212 static u32 seqnum_prev;
@@ -350,6 +351,11 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
350 brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name); 351 brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
351 break; 352 break;
352 353
354 case BRCMF_E_ESCAN_RESULT:
355 brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
356 datalen = 0;
357 break;
358
353 case BRCMF_E_PFN_NET_FOUND: 359 case BRCMF_E_PFN_NET_FOUND:
354 case BRCMF_E_PFN_NET_LOST: 360 case BRCMF_E_PFN_NET_LOST:
355 case BRCMF_E_PFN_SCAN_COMPLETE: 361 case BRCMF_E_PFN_SCAN_COMPLETE:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 4a27ca03f5bc..65cf8f92cb3e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -691,11 +691,342 @@ scan_out:
691 return err; 691 return err;
692} 692}
693 693
694static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
695 struct cfg80211_scan_request *request)
696{
697 u32 n_ssids;
698 u32 n_channels;
699 s32 i;
700 s32 offset;
701 __le16 chanspec;
702 u16 channel;
703 struct ieee80211_channel *req_channel;
704 char *ptr;
705 struct brcmf_ssid ssid;
706
707 memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
708 params_le->bss_type = DOT11_BSSTYPE_ANY;
709 params_le->scan_type = 0;
710 params_le->channel_num = 0;
711 params_le->nprobes = cpu_to_le32(-1);
712 params_le->active_time = cpu_to_le32(-1);
713 params_le->passive_time = cpu_to_le32(-1);
714 params_le->home_time = cpu_to_le32(-1);
715 memset(&params_le->ssid_le, 0, sizeof(params_le->ssid_le));
716
717 /* if request is null exit so it will be all channel broadcast scan */
718 if (!request)
719 return;
720
721 n_ssids = request->n_ssids;
722 n_channels = request->n_channels;
723 /* Copy channel array if applicable */
724 WL_SCAN("### List of channelspecs to scan ### %d\n", n_channels);
725 if (n_channels > 0) {
726 for (i = 0; i < n_channels; i++) {
727 chanspec = 0;
728 req_channel = request->channels[i];
729 channel = ieee80211_frequency_to_channel(
730 req_channel->center_freq);
731 if (req_channel->band == IEEE80211_BAND_2GHZ)
732 chanspec |= WL_CHANSPEC_BAND_2G;
733 else
734 chanspec |= WL_CHANSPEC_BAND_5G;
735
736 if (req_channel->flags & IEEE80211_CHAN_NO_HT40) {
737 chanspec |= WL_CHANSPEC_BW_20;
738 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
739 } else {
740 chanspec |= WL_CHANSPEC_BW_40;
741 if (req_channel->flags &
742 IEEE80211_CHAN_NO_HT40PLUS)
743 chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
744 else
745 chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
746 }
747
748 params_le->channel_list[i] =
749 (channel & WL_CHANSPEC_CHAN_MASK) |
750 chanspec;
751 WL_SCAN("Chan : %d, Channel spec: %x\n",
752 channel, params_le->channel_list[i]);
753 params_le->channel_list[i] =
754 cpu_to_le16(params_le->channel_list[i]);
755 }
756 } else {
757 WL_SCAN("Scanning all channels\n");
758 }
759 /* Copy ssid array if applicable */
760 WL_SCAN("### List of SSIDs to scan ### %d\n", n_ssids);
761 if (n_ssids > 0) {
762 offset = offsetof(struct brcmf_scan_params_le, channel_list) +
763 n_channels * sizeof(u16);
764 offset = roundup(offset, sizeof(u32));
765 ptr = (char *)params_le + offset;
766 for (i = 0; i < n_ssids; i++) {
767 memset(&ssid, 0, sizeof(ssid));
768 ssid.SSID_len = cpu_to_le32(request->ssids[i].ssid_len);
769 memcpy(ssid.SSID, request->ssids[i].ssid,
770 request->ssids[i].ssid_len);
771 if (!ssid.SSID_len)
772 WL_SCAN("%d: Broadcast scan\n", i);
773 else
774 WL_SCAN("%d: scan for %s size =%d\n", i,
775 ssid.SSID, ssid.SSID_len);
776 memcpy(ptr, &ssid, sizeof(ssid));
777 ptr += sizeof(ssid);
778 }
779 } else {
780 WL_SCAN("Broadcast scan %p\n", request->ssids);
781 if ((request->ssids) && request->ssids->ssid_len) {
782 WL_SCAN("SSID %s len=%d\n", params_le->ssid_le.SSID,
783 request->ssids->ssid_len);
784 params_le->ssid_le.SSID_len =
785 cpu_to_le32(request->ssids->ssid_len);
786 memcpy(&params_le->ssid_le.SSID, request->ssids->ssid,
787 request->ssids->ssid_len);
788 }
789 }
790 /* Adding mask to channel numbers */
791 params_le->channel_num =
792 cpu_to_le32((n_ssids << BRCMF_SCAN_PARAMS_NSSID_SHIFT) |
793 (n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
794}
795
796static s32
797brcmf_notify_escan_complete(struct brcmf_cfg80211_priv *cfg_priv,
798 struct net_device *ndev,
799 bool aborted, bool fw_abort)
800{
801 struct brcmf_scan_params_le params_le;
802 struct cfg80211_scan_request *scan_request;
803 s32 err = 0;
804
805 WL_SCAN("Enter\n");
806
807 /* clear scan request, because the FW abort can cause a second call */
808 /* to this functon and might cause a double cfg80211_scan_done */
809 scan_request = cfg_priv->scan_request;
810 cfg_priv->scan_request = NULL;
811
812 if (timer_pending(&cfg_priv->escan_timeout))
813 del_timer_sync(&cfg_priv->escan_timeout);
814
815 if (fw_abort) {
816 /* Do a scan abort to stop the driver's scan engine */
817 WL_SCAN("ABORT scan in firmware\n");
818 memset(&params_le, 0, sizeof(params_le));
819 memcpy(params_le.bssid, ether_bcast, ETH_ALEN);
820 params_le.bss_type = DOT11_BSSTYPE_ANY;
821 params_le.scan_type = 0;
822 params_le.channel_num = cpu_to_le32(1);
823 params_le.nprobes = cpu_to_le32(1);
824 params_le.active_time = cpu_to_le32(-1);
825 params_le.passive_time = cpu_to_le32(-1);
826 params_le.home_time = cpu_to_le32(-1);
827 /* Scan is aborted by setting channel_list[0] to -1 */
828 params_le.channel_list[0] = cpu_to_le16(-1);
829 /* E-Scan (or anyother type) can be aborted by SCAN */
830 err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &params_le,
831 sizeof(params_le));
832 if (err)
833 WL_ERR("Scan abort failed\n");
834 }
835 if (scan_request) {
836 WL_SCAN("ESCAN Completed scan: %s\n",
837 aborted ? "Aborted" : "Done");
838 cfg80211_scan_done(scan_request, aborted);
839 brcmf_set_mpc(ndev, 1);
840 }
841 if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
842 WL_ERR("Scan complete while device not scanning\n");
843 return -EPERM;
844 }
845
846 return err;
847}
848
849static s32
850brcmf_run_escan(struct brcmf_cfg80211_priv *cfg_priv, struct net_device *ndev,
851 struct cfg80211_scan_request *request, u16 action)
852{
853 s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
854 offsetof(struct brcmf_escan_params_le, params_le);
855 struct brcmf_escan_params_le *params;
856 s32 err = 0;
857
858 WL_SCAN("E-SCAN START\n");
859
860 if (request != NULL) {
861 /* Allocate space for populating ssids in struct */
862 params_size += sizeof(u32) * ((request->n_channels + 1) / 2);
863
864 /* Allocate space for populating ssids in struct */
865 params_size += sizeof(struct brcmf_ssid) * request->n_ssids;
866 }
867
868 params = kzalloc(params_size, GFP_KERNEL);
869 if (!params) {
870 err = -ENOMEM;
871 goto exit;
872 }
873 BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
874 brcmf_escan_prep(&params->params_le, request);
875 params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
876 params->action = cpu_to_le16(action);
877 params->sync_id = cpu_to_le16(0x1234);
878
879 err = brcmf_dev_iovar_setbuf(ndev, "escan", params, params_size,
880 cfg_priv->escan_ioctl_buf, BRCMF_DCMD_MEDLEN);
881 if (err) {
882 if (err == -EBUSY)
883 WL_INFO("system busy : escan canceled\n");
884 else
885 WL_ERR("error (%d)\n", err);
886 }
887
888 kfree(params);
889exit:
890 return err;
891}
892
893static s32
894brcmf_do_escan(struct brcmf_cfg80211_priv *cfg_priv, struct wiphy *wiphy,
895 struct net_device *ndev, struct cfg80211_scan_request *request)
896{
897 s32 err;
898 __le32 passive_scan;
899 struct brcmf_scan_results *results;
900
901 WL_SCAN("Enter\n");
902 cfg_priv->escan_info.ndev = ndev;
903 cfg_priv->escan_info.wiphy = wiphy;
904 cfg_priv->escan_info.escan_state = WL_ESCAN_STATE_SCANNING;
905 passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
906 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
907 &passive_scan, sizeof(passive_scan));
908 if (err) {
909 WL_ERR("error (%d)\n", err);
910 return err;
911 }
912 brcmf_set_mpc(ndev, 0);
913 results = (struct brcmf_scan_results *)cfg_priv->escan_info.escan_buf;
914 results->version = 0;
915 results->count = 0;
916 results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
917
918 err = brcmf_run_escan(cfg_priv, ndev, request, WL_ESCAN_ACTION_START);
919 if (err)
920 brcmf_set_mpc(ndev, 1);
921 return err;
922}
923
924static s32
925brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
926 struct cfg80211_scan_request *request,
927 struct cfg80211_ssid *this_ssid)
928{
929 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
930 struct cfg80211_ssid *ssids;
931 struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int;
932 __le32 passive_scan;
933 bool escan_req;
934 bool spec_scan;
935 s32 err;
936 u32 SSID_len;
937
938 WL_SCAN("START ESCAN\n");
939
940 if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
941 WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status);
942 return -EAGAIN;
943 }
944 if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) {
945 WL_ERR("Scanning being aborted : status (%lu)\n",
946 cfg_priv->status);
947 return -EAGAIN;
948 }
949 if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) {
950 WL_ERR("Connecting : status (%lu)\n",
951 cfg_priv->status);
952 return -EAGAIN;
953 }
954
955 /* Arm scan timeout timer */
956 mod_timer(&cfg_priv->escan_timeout, jiffies +
957 WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
958
959 escan_req = false;
960 if (request) {
961 /* scan bss */
962 ssids = request->ssids;
963 escan_req = true;
964 } else {
965 /* scan in ibss */
966 /* we don't do escan in ibss */
967 ssids = this_ssid;
968 }
969
970 cfg_priv->scan_request = request;
971 set_bit(WL_STATUS_SCANNING, &cfg_priv->status);
972 if (escan_req) {
973 err = brcmf_do_escan(cfg_priv, wiphy, ndev, request);
974 if (!err)
975 return err;
976 else
977 goto scan_out;
978 } else {
979 WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
980 ssids->ssid, ssids->ssid_len);
981 memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
982 SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
983 sr->ssid_le.SSID_len = cpu_to_le32(0);
984 spec_scan = false;
985 if (SSID_len) {
986 memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
987 sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
988 spec_scan = true;
989 } else
990 WL_SCAN("Broadcast scan\n");
991
992 passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
993 err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
994 &passive_scan, sizeof(passive_scan));
995 if (err) {
996 WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
997 goto scan_out;
998 }
999 brcmf_set_mpc(ndev, 0);
1000 err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
1001 sizeof(sr->ssid_le));
1002 if (err) {
1003 if (err == -EBUSY)
1004 WL_INFO("BUSY: scan for \"%s\" canceled\n",
1005 sr->ssid_le.SSID);
1006 else
1007 WL_ERR("WLC_SCAN error (%d)\n", err);
1008
1009 brcmf_set_mpc(ndev, 1);
1010 goto scan_out;
1011 }
1012 }
1013
1014 return 0;
1015
1016scan_out:
1017 clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
1018 if (timer_pending(&cfg_priv->escan_timeout))
1019 del_timer_sync(&cfg_priv->escan_timeout);
1020 cfg_priv->scan_request = NULL;
1021 return err;
1022}
1023
694static s32 1024static s32
695brcmf_cfg80211_scan(struct wiphy *wiphy, 1025brcmf_cfg80211_scan(struct wiphy *wiphy,
696 struct cfg80211_scan_request *request) 1026 struct cfg80211_scan_request *request)
697{ 1027{
698 struct net_device *ndev = request->wdev->netdev; 1028 struct net_device *ndev = request->wdev->netdev;
1029 struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
699 s32 err = 0; 1030 s32 err = 0;
700 1031
701 WL_TRACE("Enter\n"); 1032 WL_TRACE("Enter\n");
@@ -703,7 +1034,11 @@ brcmf_cfg80211_scan(struct wiphy *wiphy,
703 if (!check_sys_up(wiphy)) 1034 if (!check_sys_up(wiphy))
704 return -EIO; 1035 return -EIO;
705 1036
706 err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL); 1037 if (cfg_priv->iscan_on)
1038 err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL);
1039 else if (cfg_priv->escan_on)
1040 err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
1041
707 if (err) 1042 if (err)
708 WL_ERR("scan error (%d)\n", err); 1043 WL_ERR("scan error (%d)\n", err);
709 1044
@@ -2472,6 +2807,175 @@ static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv)
2472 return err; 2807 return err;
2473} 2808}
2474 2809
2810static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
2811{
2812 struct brcmf_cfg80211_priv *cfg_priv =
2813 container_of(work, struct brcmf_cfg80211_priv,
2814 escan_timeout_work);
2815
2816 brcmf_notify_escan_complete(cfg_priv,
2817 cfg_priv->escan_info.ndev, true, true);
2818}
2819
2820static void brcmf_escan_timeout(unsigned long data)
2821{
2822 struct brcmf_cfg80211_priv *cfg_priv =
2823 (struct brcmf_cfg80211_priv *)data;
2824
2825 if (cfg_priv->scan_request) {
2826 WL_ERR("timer expired\n");
2827 if (cfg_priv->escan_on)
2828 schedule_work(&cfg_priv->escan_timeout_work);
2829 }
2830}
2831
2832static s32
2833brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
2834 struct brcmf_bss_info_le *bss_info_le)
2835{
2836 if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
2837 (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
2838 CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
2839 bss_info_le->SSID_len == bss->SSID_len &&
2840 !memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
2841 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
2842 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
2843 /* preserve max RSSI if the measurements are
2844 * both on-channel or both off-channel
2845 */
2846 if (bss_info_le->RSSI > bss->RSSI)
2847 bss->RSSI = bss_info_le->RSSI;
2848 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
2849 (bss_info_le->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
2850 /* preserve the on-channel rssi measurement
2851 * if the new measurement is off channel
2852 */
2853 bss->RSSI = bss_info_le->RSSI;
2854 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
2855 }
2856 return 1;
2857 }
2858 return 0;
2859}
2860
2861static s32
2862brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_priv *cfg_priv,
2863 struct net_device *ndev,
2864 const struct brcmf_event_msg *e, void *data)
2865{
2866 s32 status;
2867 s32 err = 0;
2868 struct brcmf_escan_result_le *escan_result_le;
2869 struct brcmf_bss_info_le *bss_info_le;
2870 struct brcmf_bss_info_le *bss = NULL;
2871 u32 bi_length;
2872 struct brcmf_scan_results *list;
2873 u32 i;
2874
2875 status = be32_to_cpu(e->status);
2876
2877 if (!ndev || !cfg_priv->escan_on ||
2878 !test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
2879 WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n",
2880 ndev, cfg_priv->escan_on,
2881 !test_bit(WL_STATUS_SCANNING, &cfg_priv->status));
2882 return -EPERM;
2883 }
2884
2885 if (status == BRCMF_E_STATUS_PARTIAL) {
2886 WL_SCAN("ESCAN Partial result\n");
2887 escan_result_le = (struct brcmf_escan_result_le *) data;
2888 if (!escan_result_le) {
2889 WL_ERR("Invalid escan result (NULL pointer)\n");
2890 goto exit;
2891 }
2892 if (!cfg_priv->scan_request) {
2893 WL_SCAN("result without cfg80211 request\n");
2894 goto exit;
2895 }
2896
2897 if (le16_to_cpu(escan_result_le->bss_count) != 1) {
2898 WL_ERR("Invalid bss_count %d: ignoring\n",
2899 escan_result_le->bss_count);
2900 goto exit;
2901 }
2902 bss_info_le = &escan_result_le->bss_info_le;
2903
2904 bi_length = le32_to_cpu(bss_info_le->length);
2905 if (bi_length != (le32_to_cpu(escan_result_le->buflen) -
2906 WL_ESCAN_RESULTS_FIXED_SIZE)) {
2907 WL_ERR("Invalid bss_info length %d: ignoring\n",
2908 bi_length);
2909 goto exit;
2910 }
2911
2912 if (!(cfg_to_wiphy(cfg_priv)->interface_modes &
2913 BIT(NL80211_IFTYPE_ADHOC))) {
2914 if (le16_to_cpu(bss_info_le->capability) &
2915 WLAN_CAPABILITY_IBSS) {
2916 WL_ERR("Ignoring IBSS result\n");
2917 goto exit;
2918 }
2919 }
2920
2921 list = (struct brcmf_scan_results *)
2922 cfg_priv->escan_info.escan_buf;
2923 if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
2924 WL_ERR("Buffer is too small: ignoring\n");
2925 goto exit;
2926 }
2927
2928 for (i = 0; i < list->count; i++) {
2929 bss = bss ? (struct brcmf_bss_info_le *)
2930 ((unsigned char *)bss +
2931 le32_to_cpu(bss->length)) : list->bss_info_le;
2932 if (brcmf_compare_update_same_bss(bss, bss_info_le))
2933 goto exit;
2934 }
2935 memcpy(&(cfg_priv->escan_info.escan_buf[list->buflen]),
2936 bss_info_le, bi_length);
2937 list->version = le32_to_cpu(bss_info_le->version);
2938 list->buflen += bi_length;
2939 list->count++;
2940 } else {
2941 cfg_priv->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2942 if (cfg_priv->scan_request) {
2943 cfg_priv->bss_list = (struct brcmf_scan_results *)
2944 cfg_priv->escan_info.escan_buf;
2945 brcmf_inform_bss(cfg_priv);
2946 if (status == BRCMF_E_STATUS_SUCCESS) {
2947 WL_SCAN("ESCAN Completed\n");
2948 brcmf_notify_escan_complete(cfg_priv, ndev,
2949 false, false);
2950 } else {
2951 WL_ERR("ESCAN Aborted, Event 0x%x\n", status);
2952 brcmf_notify_escan_complete(cfg_priv, ndev,
2953 true, false);
2954 }
2955 brcmf_set_mpc(ndev, 1);
2956 } else
2957 WL_ERR("Unexpected scan result 0x%x\n", status);
2958 }
2959exit:
2960 return err;
2961}
2962
2963static void brcmf_init_escan(struct brcmf_cfg80211_priv *cfg_priv)
2964{
2965
2966 if (cfg_priv->escan_on) {
2967 cfg_priv->el.handler[BRCMF_E_ESCAN_RESULT] =
2968 brcmf_cfg80211_escan_handler;
2969 cfg_priv->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
2970 /* Init scan_timeout timer */
2971 init_timer(&cfg_priv->escan_timeout);
2972 cfg_priv->escan_timeout.data = (unsigned long) cfg_priv;
2973 cfg_priv->escan_timeout.function = brcmf_escan_timeout;
2974 INIT_WORK(&cfg_priv->escan_timeout_work,
2975 brcmf_cfg80211_escan_timeout_worker);
2976 }
2977}
2978
2475static __always_inline void brcmf_delay(u32 ms) 2979static __always_inline void brcmf_delay(u32 ms)
2476{ 2980{
2477 if (ms < 1000 / HZ) { 2981 if (ms < 1000 / HZ) {
@@ -3240,6 +3744,8 @@ static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
3240 cfg_priv->profile = NULL; 3744 cfg_priv->profile = NULL;
3241 kfree(cfg_priv->scan_req_int); 3745 kfree(cfg_priv->scan_req_int);
3242 cfg_priv->scan_req_int = NULL; 3746 cfg_priv->scan_req_int = NULL;
3747 kfree(cfg_priv->escan_ioctl_buf);
3748 cfg_priv->escan_ioctl_buf = NULL;
3243 kfree(cfg_priv->dcmd_buf); 3749 kfree(cfg_priv->dcmd_buf);
3244 cfg_priv->dcmd_buf = NULL; 3750 cfg_priv->dcmd_buf = NULL;
3245 kfree(cfg_priv->extra_buf); 3751 kfree(cfg_priv->extra_buf);
@@ -3268,6 +3774,9 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
3268 GFP_KERNEL); 3774 GFP_KERNEL);
3269 if (!cfg_priv->scan_req_int) 3775 if (!cfg_priv->scan_req_int)
3270 goto init_priv_mem_out; 3776 goto init_priv_mem_out;
3777 cfg_priv->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
3778 if (!cfg_priv->escan_ioctl_buf)
3779 goto init_priv_mem_out;
3271 cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); 3780 cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
3272 if (!cfg_priv->dcmd_buf) 3781 if (!cfg_priv->dcmd_buf)
3273 goto init_priv_mem_out; 3782 goto init_priv_mem_out;
@@ -3404,8 +3913,17 @@ static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
3404 3913
3405 cfg_priv->scan_request = NULL; 3914 cfg_priv->scan_request = NULL;
3406 cfg_priv->pwr_save = true; 3915 cfg_priv->pwr_save = true;
3916#ifdef CONFIG_BRCMISCAN
3407 cfg_priv->iscan_on = true; /* iscan on & off switch. 3917 cfg_priv->iscan_on = true; /* iscan on & off switch.
3408 we enable iscan per default */ 3918 we enable iscan per default */
3919 cfg_priv->escan_on = false; /* escan on & off switch.
3920 we disable escan per default */
3921#else
3922 cfg_priv->iscan_on = false; /* iscan on & off switch.
3923 we disable iscan per default */
3924 cfg_priv->escan_on = true; /* escan on & off switch.
3925 we enable escan per default */
3926#endif
3409 cfg_priv->roam_on = true; /* roam on & off switch. 3927 cfg_priv->roam_on = true; /* roam on & off switch.
3410 we enable roam per default */ 3928 we enable roam per default */
3411 3929
@@ -3423,6 +3941,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
3423 err = brcmf_init_iscan(cfg_priv); 3941 err = brcmf_init_iscan(cfg_priv);
3424 if (err) 3942 if (err)
3425 return err; 3943 return err;
3944 brcmf_init_escan(cfg_priv);
3426 brcmf_init_conf(cfg_priv->conf); 3945 brcmf_init_conf(cfg_priv->conf);
3427 brcmf_init_prof(cfg_priv->profile); 3946 brcmf_init_prof(cfg_priv->profile);
3428 brcmf_link_down(cfg_priv); 3947 brcmf_link_down(cfg_priv);
@@ -3581,6 +4100,7 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
3581 setbit(eventmask, BRCMF_E_TXFAIL); 4100 setbit(eventmask, BRCMF_E_TXFAIL);
3582 setbit(eventmask, BRCMF_E_JOIN_START); 4101 setbit(eventmask, BRCMF_E_JOIN_START);
3583 setbit(eventmask, BRCMF_E_SCAN_COMPLETE); 4102 setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
4103 setbit(eventmask, BRCMF_E_ESCAN_RESULT);
3584 4104
3585 brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, 4105 brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
3586 iovbuf, sizeof(iovbuf)); 4106 iovbuf, sizeof(iovbuf));
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index b5d9b36df3d0..3b2129738d30 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -123,6 +123,13 @@ do { \
123#define WL_SCAN_UNASSOC_TIME 40 123#define WL_SCAN_UNASSOC_TIME 40
124#define WL_SCAN_PASSIVE_TIME 120 124#define WL_SCAN_PASSIVE_TIME 120
125 125
126#define WL_ESCAN_BUF_SIZE (1024 * 64)
127#define WL_ESCAN_TIMER_INTERVAL_MS 8000 /* E-Scan timeout */
128
129#define WL_ESCAN_ACTION_START 1
130#define WL_ESCAN_ACTION_CONTINUE 2
131#define WL_ESCAN_ACTION_ABORT 3
132
126/* dongle status */ 133/* dongle status */
127enum wl_status { 134enum wl_status {
128 WL_STATUS_READY, 135 WL_STATUS_READY,
@@ -275,6 +282,19 @@ struct brcmf_cfg80211_pmk_list {
275 struct pmkid foo[MAXPMKID - 1]; 282 struct pmkid foo[MAXPMKID - 1];
276}; 283};
277 284
285/* dongle escan state */
286enum wl_escan_state {
287 WL_ESCAN_STATE_IDLE,
288 WL_ESCAN_STATE_SCANNING
289};
290
291struct escan_info {
292 u32 escan_state;
293 u8 escan_buf[WL_ESCAN_BUF_SIZE];
294 struct wiphy *wiphy;
295 struct net_device *ndev;
296};
297
278/* dongle private data of cfg80211 interface */ 298/* dongle private data of cfg80211 interface */
279struct brcmf_cfg80211_priv { 299struct brcmf_cfg80211_priv {
280 struct wireless_dev *wdev; /* representing wl cfg80211 device */ 300 struct wireless_dev *wdev; /* representing wl cfg80211 device */
@@ -315,6 +335,11 @@ struct brcmf_cfg80211_priv {
315 u8 *dcmd_buf; /* dcmd buffer */ 335 u8 *dcmd_buf; /* dcmd buffer */
316 u8 *extra_buf; /* maily to grab assoc information */ 336 u8 *extra_buf; /* maily to grab assoc information */
317 struct dentry *debugfsdir; 337 struct dentry *debugfsdir;
338 bool escan_on; /* escan on/off switch */
339 struct escan_info escan_info; /* escan information */
340 struct timer_list escan_timeout; /* Timer for catch scan timeout */
341 struct work_struct escan_timeout_work; /* scan timeout worker */
342 u8 *escan_ioctl_buf;
318 u8 ci[0] __aligned(NETDEV_ALIGN); 343 u8 ci[0] __aligned(NETDEV_ALIGN);
319}; 344};
320 345