aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2011-09-19 12:15:03 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2011-09-22 03:07:59 -0400
commit1aaa8c7469db14c3cbb0776afda0fb007eb43f46 (patch)
tree0c7e13a2c9efd713f8a4b65617c639f742c2eea4
parent3b25ed186fc3ac8d2517332bfbd5c44016c10f82 (diff)
ath6kl: Replace internal node table with cfg80211 BSS table
The internal node table in ath6kl was not really used for any useful purpose. It was just used to collect scan results during a scan and then provide them in a burst to cfg80211 at the completion of the scan. There is no point in doing this since cfg80211 is perfectly capable of maintaining the BSS table and the BSS inform messages are sent in separate function calls anyway. This provides more complete information in the cfg80211 BSS table since this allows Beacon and Probe Response frames to be distinguished and IEs from them reported separately. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c296
1 files changed, 45 insertions, 251 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 24f0e3eb4211..ff13e0bc646b 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -910,277 +910,74 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len)
910 return 0; 910 return 0;
911} 911}
912 912
913static int ath6kl_wlan_parse_beacon(u8 *buf, int frame_len,
914 struct ath6kl_common_ie *cie)
915{
916 u8 *frm, *efrm;
917 u8 elemid_ssid = false;
918
919 frm = buf;
920 efrm = (u8 *) (frm + frame_len);
921
922 /*
923 * beacon/probe response frame format
924 * [8] time stamp
925 * [2] beacon interval
926 * [2] capability information
927 * [tlv] ssid
928 * [tlv] supported rates
929 * [tlv] country information
930 * [tlv] parameter set (FH/DS)
931 * [tlv] erp information
932 * [tlv] extended supported rates
933 * [tlv] WMM
934 * [tlv] WPA or RSN
935 * [tlv] Atheros Advanced Capabilities
936 */
937 if ((efrm - frm) < 12)
938 return -EINVAL;
939
940 memset(cie, 0, sizeof(*cie));
941
942 cie->ie_tstamp = frm;
943 frm += 8;
944 cie->ie_beaconInt = *(u16 *) frm;
945 frm += 2;
946 cie->ie_capInfo = *(u16 *) frm;
947 frm += 2;
948 cie->ie_chan = 0;
949
950 while (frm < efrm) {
951 switch (*frm) {
952 case WLAN_EID_SSID:
953 if (!elemid_ssid) {
954 cie->ie_ssid = frm;
955 elemid_ssid = true;
956 }
957 break;
958 case WLAN_EID_SUPP_RATES:
959 cie->ie_rates = frm;
960 break;
961 case WLAN_EID_COUNTRY:
962 cie->ie_country = frm;
963 break;
964 case WLAN_EID_FH_PARAMS:
965 break;
966 case WLAN_EID_DS_PARAMS:
967 cie->ie_chan = frm[2];
968 break;
969 case WLAN_EID_TIM:
970 cie->ie_tim = frm;
971 break;
972 case WLAN_EID_IBSS_PARAMS:
973 break;
974 case WLAN_EID_EXT_SUPP_RATES:
975 cie->ie_xrates = frm;
976 break;
977 case WLAN_EID_ERP_INFO:
978 if (frm[1] != 1)
979 return -EINVAL;
980
981 cie->ie_erp = frm[2];
982 break;
983 case WLAN_EID_RSN:
984 cie->ie_rsn = frm;
985 break;
986 case WLAN_EID_HT_CAPABILITY:
987 cie->ie_htcap = frm;
988 break;
989 case WLAN_EID_HT_INFORMATION:
990 cie->ie_htop = frm;
991 break;
992 case WLAN_EID_VENDOR_SPECIFIC:
993 if (frm[1] > 3 && frm[2] == 0x00 && frm[3] == 0x50 &&
994 frm[4] == 0xf2) {
995 /* OUT Type (00:50:F2) */
996
997 if (frm[5] == WPA_OUI_TYPE) {
998 /* WPA OUT */
999 cie->ie_wpa = frm;
1000 } else if (frm[5] == WMM_OUI_TYPE) {
1001 /* WMM OUT */
1002 cie->ie_wmm = frm;
1003 } else if (frm[5] == WSC_OUT_TYPE) {
1004 /* WSC OUT */
1005 cie->ie_wsc = frm;
1006 }
1007
1008 } else if (frm[1] > 3 && frm[2] == 0x00
1009 && frm[3] == 0x03 && frm[4] == 0x7f
1010 && frm[5] == ATH_OUI_TYPE) {
1011 /* Atheros OUI (00:03:7f) */
1012 cie->ie_ath = frm;
1013 }
1014 break;
1015 default:
1016 break;
1017 }
1018 frm += frm[1] + 2;
1019 }
1020
1021 if ((cie->ie_rates == NULL)
1022 || (cie->ie_rates[1] > ATH6KL_RATE_MAXSIZE))
1023 return -EINVAL;
1024
1025 if ((cie->ie_ssid == NULL)
1026 || (cie->ie_ssid[1] > IEEE80211_MAX_SSID_LEN))
1027 return -EINVAL;
1028
1029 return 0;
1030}
1031
1032static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) 913static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len)
1033{ 914{
1034 struct bss *bss = NULL;
1035 struct wmi_bss_info_hdr *bih; 915 struct wmi_bss_info_hdr *bih;
1036 u8 cached_ssid_len = 0; 916 u8 *buf;
1037 u8 cached_ssid[IEEE80211_MAX_SSID_LEN] = { 0 }; 917 struct ieee80211_channel *channel;
1038 u8 beacon_ssid_len = 0; 918 struct ath6kl *ar = wmi->parent_dev;
1039 u8 *buf, *ie_ssid; 919 struct ieee80211_mgmt *mgmt;
1040 u8 *ni_buf; 920 struct cfg80211_bss *bss;
1041 int buf_len;
1042
1043 int ret;
1044 921
1045 if (len <= sizeof(struct wmi_bss_info_hdr)) 922 if (len <= sizeof(struct wmi_bss_info_hdr))
1046 return -EINVAL; 923 return -EINVAL;
1047 924
1048 bih = (struct wmi_bss_info_hdr *) datap; 925 bih = (struct wmi_bss_info_hdr *) datap;
1049 bss = wlan_find_node(&wmi->parent_dev->scan_table, bih->bssid);
1050
1051 if (a_sle16_to_cpu(bih->rssi) > 0) {
1052 if (bss == NULL)
1053 return 0;
1054 else
1055 bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
1056 }
1057
1058 buf = datap + sizeof(struct wmi_bss_info_hdr); 926 buf = datap + sizeof(struct wmi_bss_info_hdr);
1059 len -= sizeof(struct wmi_bss_info_hdr); 927 len -= sizeof(struct wmi_bss_info_hdr);
1060 928
1061 ath6kl_dbg(ATH6KL_DBG_WMI, 929 ath6kl_dbg(ATH6KL_DBG_WMI,
1062 "bss info evt - ch %u, rssi %02x, bssid \"%pM\"\n", 930 "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" "
1063 bih->ch, a_sle16_to_cpu(bih->rssi), bih->bssid); 931 "frame_type=%d\n",
1064 932 bih->ch, bih->snr, a_sle16_to_cpu(bih->rssi), bih->bssid,
1065 if (bss != NULL) { 933 bih->frame_type);
1066 /*
1067 * Free up the node. We are about to allocate a new node.
1068 * In case of hidden AP, beacon will not have ssid,
1069 * but a directed probe response will have it,
1070 * so cache the probe-resp-ssid if already present.
1071 */
1072 if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE)) {
1073 ie_ssid = bss->ni_cie.ie_ssid;
1074 if (ie_ssid && (ie_ssid[1] <= IEEE80211_MAX_SSID_LEN) &&
1075 (ie_ssid[2] != 0)) {
1076 cached_ssid_len = ie_ssid[1];
1077 memcpy(cached_ssid, ie_ssid + 2,
1078 cached_ssid_len);
1079 }
1080 }
1081
1082 /*
1083 * Use the current average rssi of associated AP base on
1084 * assumption
1085 * 1. Most os with GUI will update RSSI by
1086 * ath6kl_wmi_get_stats_cmd() periodically.
1087 * 2. ath6kl_wmi_get_stats_cmd(..) will be called when calling
1088 * ath6kl_wmi_startscan_cmd(...)
1089 * The average value of RSSI give end-user better feeling for
1090 * instance value of scan result. It also sync up RSSI info
1091 * in GUI between scan result and RSSI signal icon.
1092 */
1093 if (memcmp(wmi->parent_dev->bssid, bih->bssid, ETH_ALEN) == 0) {
1094 bih->rssi = a_cpu_to_sle16(bss->ni_rssi);
1095 bih->snr = bss->ni_snr;
1096 }
1097
1098 wlan_node_reclaim(&wmi->parent_dev->scan_table, bss);
1099 }
1100
1101 /*
1102 * beacon/probe response frame format
1103 * [8] time stamp
1104 * [2] beacon interval
1105 * [2] capability information
1106 * [tlv] ssid
1107 */
1108 beacon_ssid_len = buf[SSID_IE_LEN_INDEX];
1109
1110 /*
1111 * If ssid is cached for this hidden AP, then change
1112 * buffer len accordingly.
1113 */
1114 if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) &&
1115 (cached_ssid_len != 0) &&
1116 (beacon_ssid_len == 0 || (cached_ssid_len > beacon_ssid_len &&
1117 buf[SSID_IE_LEN_INDEX + 1] == 0))) {
1118
1119 len += (cached_ssid_len - beacon_ssid_len);
1120 }
1121 934
1122 bss = wlan_node_alloc(len); 935 if (bih->frame_type != BEACON_FTYPE &&
1123 if (!bss) 936 bih->frame_type != PROBERESP_FTYPE)
1124 return -ENOMEM; 937 return 0; /* Only update BSS table for now */
1125 938
1126 bss->ni_snr = bih->snr; 939 channel = ieee80211_get_channel(ar->wdev->wiphy, le16_to_cpu(bih->ch));
1127 bss->ni_rssi = a_sle16_to_cpu(bih->rssi); 940 if (channel == NULL)
941 return -EINVAL;
1128 942
1129 if (WARN_ON(!bss->ni_buf)) 943 if (len < 8 + 2 + 2)
1130 return -EINVAL; 944 return -EINVAL;
1131 945
1132 /* 946 /*
1133 * In case of hidden AP, beacon will not have ssid, 947 * In theory, use of cfg80211_inform_bss() would be more natural here
1134 * but a directed probe response will have it, 948 * since we do not have the full frame. However, at least for now,
1135 * so place the cached-ssid(probe-resp) in the bss info. 949 * cfg80211 can only distinguish Beacon and Probe Response frames from
950 * each other when using cfg80211_inform_bss_frame(), so let's build a
951 * fake IEEE 802.11 header to be able to take benefit of this.
1136 */ 952 */
1137 if (wmi->is_probe_ssid && (bih->frame_type == BEACON_FTYPE) && 953 mgmt = kmalloc(24 + len, GFP_ATOMIC);
1138 (cached_ssid_len != 0) && 954 if (mgmt == NULL)
1139 (beacon_ssid_len == 0 || (beacon_ssid_len && 955 return -EINVAL;
1140 buf[SSID_IE_LEN_INDEX + 1] == 0))) {
1141 ni_buf = bss->ni_buf;
1142 buf_len = len;
1143
1144 /*
1145 * Copy the first 14 bytes:
1146 * time-stamp(8), beacon-interval(2),
1147 * cap-info(2), ssid-id(1), ssid-len(1).
1148 */
1149 memcpy(ni_buf, buf, SSID_IE_LEN_INDEX + 1);
1150
1151 ni_buf[SSID_IE_LEN_INDEX] = cached_ssid_len;
1152 ni_buf += (SSID_IE_LEN_INDEX + 1);
1153
1154 buf += (SSID_IE_LEN_INDEX + 1);
1155 buf_len -= (SSID_IE_LEN_INDEX + 1);
1156
1157 memcpy(ni_buf, cached_ssid, cached_ssid_len);
1158 ni_buf += cached_ssid_len;
1159
1160 buf += beacon_ssid_len;
1161 buf_len -= beacon_ssid_len;
1162
1163 if (cached_ssid_len > beacon_ssid_len)
1164 buf_len -= (cached_ssid_len - beacon_ssid_len);
1165
1166 memcpy(ni_buf, buf, buf_len);
1167 } else
1168 memcpy(bss->ni_buf, buf, len);
1169 956
1170 bss->ni_framelen = len; 957 if (bih->frame_type == BEACON_FTYPE) {
958 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
959 IEEE80211_STYPE_BEACON);
960 memset(mgmt->da, 0xff, ETH_ALEN);
961 } else {
962 struct net_device *dev = ar->net_dev;
1171 963
1172 ret = ath6kl_wlan_parse_beacon(bss->ni_buf, len, &bss->ni_cie); 964 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1173 if (ret) { 965 IEEE80211_STYPE_PROBE_RESP);
1174 wlan_node_free(bss); 966 memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
1175 return -EINVAL;
1176 } 967 }
968 mgmt->duration = cpu_to_le16(0);
969 memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
970 memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
971 mgmt->seq_ctrl = cpu_to_le16(0);
1177 972
1178 /* 973 memcpy(&mgmt->u.beacon, buf, len);
1179 * Update the frequency in ie_chan, overwriting of channel number 974
1180 * which is done in ath6kl_wlan_parse_beacon 975 bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, channel, mgmt,
1181 */ 976 24 + len, bih->snr * 100, GFP_ATOMIC);
1182 bss->ni_cie.ie_chan = le16_to_cpu(bih->ch); 977 kfree(mgmt);
1183 wlan_setup_node(&wmi->parent_dev->scan_table, bss, bih->bssid); 978 if (bss == NULL)
979 return -ENOMEM;
980 cfg80211_put_bss(bss);
1184 981
1185 return 0; 982 return 0;
1186} 983}
@@ -1295,9 +1092,6 @@ static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len)
1295 1092
1296 ev = (struct wmi_scan_complete_event *) datap; 1093 ev = (struct wmi_scan_complete_event *) datap;
1297 1094
1298 if (a_sle32_to_cpu(ev->status) == 0)
1299 wlan_refresh_inactive_nodes(wmi->parent_dev);
1300
1301 ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status)); 1095 ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status));
1302 wmi->is_probe_ssid = false; 1096 wmi->is_probe_ssid = false;
1303 1097