diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/cfg80211.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/cfg80211.c | 209 |
1 files changed, 44 insertions, 165 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 352d2c5da1f..6fd53e4e3fe 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c | |||
@@ -547,7 +547,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, | |||
547 | sinfo->tx_bytes = priv->stats.tx_bytes; | 547 | sinfo->tx_bytes = priv->stats.tx_bytes; |
548 | sinfo->rx_packets = priv->stats.rx_packets; | 548 | sinfo->rx_packets = priv->stats.rx_packets; |
549 | sinfo->tx_packets = priv->stats.tx_packets; | 549 | sinfo->tx_packets = priv->stats.tx_packets; |
550 | sinfo->signal = priv->w_stats.qual.level; | 550 | sinfo->signal = priv->qual_level; |
551 | sinfo->txrate.legacy = rate.rate; | 551 | sinfo->txrate.legacy = rate.rate; |
552 | 552 | ||
553 | return ret; | 553 | return ret; |
@@ -793,139 +793,6 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) | |||
793 | } | 793 | } |
794 | 794 | ||
795 | /* | 795 | /* |
796 | * This function informs the CFG802.11 subsystem of a new BSS connection. | ||
797 | * | ||
798 | * The following information are sent to the CFG802.11 subsystem | ||
799 | * to register the new BSS connection. If we do not register the new BSS, | ||
800 | * a kernel panic will result. | ||
801 | * - MAC address | ||
802 | * - Capabilities | ||
803 | * - Beacon period | ||
804 | * - RSSI value | ||
805 | * - Channel | ||
806 | * - Supported rates IE | ||
807 | * - Extended capabilities IE | ||
808 | * - DS parameter set IE | ||
809 | * - HT Capability IE | ||
810 | * - Vendor Specific IE (221) | ||
811 | * - WPA IE | ||
812 | * - RSN IE | ||
813 | */ | ||
814 | static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, | ||
815 | struct mwifiex_802_11_ssid *ssid) | ||
816 | { | ||
817 | struct mwifiex_bssdescriptor *scan_table; | ||
818 | int i, j; | ||
819 | struct ieee80211_channel *chan; | ||
820 | u8 *ie, *ie_buf; | ||
821 | u32 ie_len; | ||
822 | u8 *beacon; | ||
823 | int beacon_size; | ||
824 | u8 element_id, element_len; | ||
825 | |||
826 | #define MAX_IE_BUF 2048 | ||
827 | ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); | ||
828 | if (!ie_buf) { | ||
829 | dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", | ||
830 | __func__); | ||
831 | return -ENOMEM; | ||
832 | } | ||
833 | |||
834 | scan_table = priv->adapter->scan_table; | ||
835 | for (i = 0; i < priv->adapter->num_in_scan_table; i++) { | ||
836 | if (ssid) { | ||
837 | /* Inform specific BSS only */ | ||
838 | if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, | ||
839 | ssid->ssid_len)) | ||
840 | continue; | ||
841 | } | ||
842 | memset(ie_buf, 0, MAX_IE_BUF); | ||
843 | ie_buf[0] = WLAN_EID_SSID; | ||
844 | ie_buf[1] = scan_table[i].ssid.ssid_len; | ||
845 | memcpy(&ie_buf[sizeof(struct ieee_types_header)], | ||
846 | scan_table[i].ssid.ssid, ie_buf[1]); | ||
847 | |||
848 | ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); | ||
849 | ie_len = ie_buf[1] + sizeof(struct ieee_types_header); | ||
850 | |||
851 | ie[0] = WLAN_EID_SUPP_RATES; | ||
852 | |||
853 | for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { | ||
854 | if (!scan_table[i].supported_rates[j]) | ||
855 | break; | ||
856 | else | ||
857 | ie[j + sizeof(struct ieee_types_header)] = | ||
858 | scan_table[i].supported_rates[j]; | ||
859 | } | ||
860 | |||
861 | ie[1] = j; | ||
862 | ie_len += ie[1] + sizeof(struct ieee_types_header); | ||
863 | |||
864 | beacon = scan_table[i].beacon_buf; | ||
865 | beacon_size = scan_table[i].beacon_buf_size; | ||
866 | |||
867 | /* Skip time stamp, beacon interval and capability */ | ||
868 | |||
869 | if (beacon) { | ||
870 | beacon += sizeof(scan_table[i].beacon_period) | ||
871 | + sizeof(scan_table[i].time_stamp) + | ||
872 | +sizeof(scan_table[i].cap_info_bitmap); | ||
873 | |||
874 | beacon_size -= sizeof(scan_table[i].beacon_period) | ||
875 | + sizeof(scan_table[i].time_stamp) | ||
876 | + sizeof(scan_table[i].cap_info_bitmap); | ||
877 | } | ||
878 | |||
879 | while (beacon_size >= sizeof(struct ieee_types_header)) { | ||
880 | ie = ie_buf + ie_len; | ||
881 | element_id = *beacon; | ||
882 | element_len = *(beacon + 1); | ||
883 | if (beacon_size < (int) element_len + | ||
884 | sizeof(struct ieee_types_header)) { | ||
885 | dev_err(priv->adapter->dev, "%s: in processing" | ||
886 | " IE, bytes left < IE length\n", | ||
887 | __func__); | ||
888 | break; | ||
889 | } | ||
890 | switch (element_id) { | ||
891 | case WLAN_EID_EXT_CAPABILITY: | ||
892 | case WLAN_EID_DS_PARAMS: | ||
893 | case WLAN_EID_HT_CAPABILITY: | ||
894 | case WLAN_EID_VENDOR_SPECIFIC: | ||
895 | case WLAN_EID_RSN: | ||
896 | case WLAN_EID_BSS_AC_ACCESS_DELAY: | ||
897 | ie[0] = element_id; | ||
898 | ie[1] = element_len; | ||
899 | memcpy(&ie[sizeof(struct ieee_types_header)], | ||
900 | (u8 *) beacon | ||
901 | + sizeof(struct ieee_types_header), | ||
902 | element_len); | ||
903 | ie_len += ie[1] + | ||
904 | sizeof(struct ieee_types_header); | ||
905 | break; | ||
906 | default: | ||
907 | break; | ||
908 | } | ||
909 | beacon += element_len + | ||
910 | sizeof(struct ieee_types_header); | ||
911 | beacon_size -= element_len + | ||
912 | sizeof(struct ieee_types_header); | ||
913 | } | ||
914 | chan = ieee80211_get_channel(priv->wdev->wiphy, | ||
915 | scan_table[i].freq); | ||
916 | cfg80211_inform_bss(priv->wdev->wiphy, chan, | ||
917 | scan_table[i].mac_address, | ||
918 | 0, scan_table[i].cap_info_bitmap, | ||
919 | scan_table[i].beacon_period, | ||
920 | ie_buf, ie_len, | ||
921 | scan_table[i].rssi, GFP_KERNEL); | ||
922 | } | ||
923 | |||
924 | kfree(ie_buf); | ||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | /* | ||
929 | * This function connects with a BSS. | 796 | * This function connects with a BSS. |
930 | * | 797 | * |
931 | * This function handles both Infra and Ad-Hoc modes. It also performs | 798 | * This function handles both Infra and Ad-Hoc modes. It also performs |
@@ -937,8 +804,7 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, | |||
937 | * For Infra mode, the function returns failure if the specified SSID | 804 | * For Infra mode, the function returns failure if the specified SSID |
938 | * is not found in scan table. However, for Ad-Hoc mode, it can create | 805 | * is not found in scan table. However, for Ad-Hoc mode, it can create |
939 | * the IBSS if it does not exist. On successful completion in either case, | 806 | * the IBSS if it does not exist. On successful completion in either case, |
940 | * the function notifies the CFG802.11 subsystem of the new BSS connection, | 807 | * the function notifies the CFG802.11 subsystem of the new BSS connection. |
941 | * otherwise the kernel will panic. | ||
942 | */ | 808 | */ |
943 | static int | 809 | static int |
944 | mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, | 810 | mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, |
@@ -946,11 +812,11 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, | |||
946 | struct cfg80211_connect_params *sme, bool privacy) | 812 | struct cfg80211_connect_params *sme, bool privacy) |
947 | { | 813 | { |
948 | struct mwifiex_802_11_ssid req_ssid; | 814 | struct mwifiex_802_11_ssid req_ssid; |
949 | struct mwifiex_ssid_bssid ssid_bssid; | ||
950 | int ret, auth_type = 0; | 815 | int ret, auth_type = 0; |
816 | struct cfg80211_bss *bss = NULL; | ||
817 | u8 is_scanning_required = 0; | ||
951 | 818 | ||
952 | memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); | 819 | memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); |
953 | memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); | ||
954 | 820 | ||
955 | req_ssid.ssid_len = ssid_len; | 821 | req_ssid.ssid_len = ssid_len; |
956 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { | 822 | if (ssid_len > IEEE80211_MAX_SSID_LEN) { |
@@ -1028,30 +894,48 @@ done: | |||
1028 | return -EFAULT; | 894 | return -EFAULT; |
1029 | } | 895 | } |
1030 | 896 | ||
897 | /* | ||
898 | * Scan entries are valid for some time (15 sec). So we can save one | ||
899 | * active scan time if we just try cfg80211_get_bss first. If it fails | ||
900 | * then request scan and cfg80211_get_bss() again for final output. | ||
901 | */ | ||
902 | while (1) { | ||
903 | if (is_scanning_required) { | ||
904 | /* Do specific SSID scanning */ | ||
905 | if (mwifiex_request_scan(priv, &req_ssid)) { | ||
906 | dev_err(priv->adapter->dev, "scan error\n"); | ||
907 | return -EFAULT; | ||
908 | } | ||
909 | } | ||
1031 | 910 | ||
1032 | memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); | 911 | /* Find the BSS we want using available scan results */ |
1033 | 912 | if (mode == NL80211_IFTYPE_ADHOC) | |
1034 | if (mode != NL80211_IFTYPE_ADHOC) { | 913 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, |
1035 | if (mwifiex_find_best_bss(priv, &ssid_bssid)) | 914 | bssid, ssid, ssid_len, |
1036 | return -EFAULT; | 915 | WLAN_CAPABILITY_IBSS, |
1037 | /* Inform the BSS information to kernel, otherwise | 916 | WLAN_CAPABILITY_IBSS); |
1038 | * kernel will give a panic after successful assoc */ | 917 | else |
1039 | if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) | 918 | bss = cfg80211_get_bss(priv->wdev->wiphy, channel, |
1040 | return -EFAULT; | 919 | bssid, ssid, ssid_len, |
920 | WLAN_CAPABILITY_ESS, | ||
921 | WLAN_CAPABILITY_ESS); | ||
922 | |||
923 | if (!bss) { | ||
924 | if (is_scanning_required) { | ||
925 | dev_warn(priv->adapter->dev, "assoc: requested " | ||
926 | "bss not found in scan results\n"); | ||
927 | break; | ||
928 | } | ||
929 | is_scanning_required = 1; | ||
930 | } else { | ||
931 | dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", | ||
932 | (char *) req_ssid.ssid, bss->bssid); | ||
933 | memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN); | ||
934 | break; | ||
935 | } | ||
1041 | } | 936 | } |
1042 | 937 | ||
1043 | dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", | 938 | if (mwifiex_bss_start(priv, bss, &req_ssid)) |
1044 | (char *) req_ssid.ssid, ssid_bssid.bssid); | ||
1045 | |||
1046 | memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); | ||
1047 | |||
1048 | /* Connect to BSS by ESSID */ | ||
1049 | memset(&ssid_bssid.bssid, 0, ETH_ALEN); | ||
1050 | |||
1051 | if (!netif_queue_stopped(priv->netdev)) | ||
1052 | netif_stop_queue(priv->netdev); | ||
1053 | |||
1054 | if (mwifiex_bss_start(priv, &ssid_bssid)) | ||
1055 | return -EFAULT; | 939 | return -EFAULT; |
1056 | 940 | ||
1057 | if (mode == NL80211_IFTYPE_ADHOC) { | 941 | if (mode == NL80211_IFTYPE_ADHOC) { |
@@ -1416,13 +1300,8 @@ mwifiex_cfg80211_results(struct work_struct *work) | |||
1416 | MWIFIEX_SCAN_TYPE_ACTIVE; | 1300 | MWIFIEX_SCAN_TYPE_ACTIVE; |
1417 | scan_req->chan_list[i].scan_time = 0; | 1301 | scan_req->chan_list[i].scan_time = 0; |
1418 | } | 1302 | } |
1419 | if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { | 1303 | if (mwifiex_set_user_scan_ioctl(priv, scan_req)) |
1420 | ret = -EFAULT; | 1304 | ret = -EFAULT; |
1421 | goto done; | ||
1422 | } | ||
1423 | if (mwifiex_inform_bss_from_scan_result(priv, NULL)) | ||
1424 | ret = -EFAULT; | ||
1425 | done: | ||
1426 | priv->scan_result_status = ret; | 1305 | priv->scan_result_status = ret; |
1427 | dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", | 1306 | dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", |
1428 | __func__); | 1307 | __func__); |