aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
authorAvinash Patil <patila@marvell.com>2014-11-13 11:24:16 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-11-17 15:32:14 -0500
commit9927baa3c7244b1f80582fc7360a7662bcb648ba (patch)
tree83cf97d5dfa4cf33c6a86389f780602ac87789d9 /drivers/net/wireless/mwifiex
parent16fa5e659f3c3b2a5edfd0a40fc8d0116d9cd52b (diff)
mwifiex: add auto TDLS support
This patch adds auto TDLS support to mwifiex. Auto TDLS functionality works as follows: 1. Whenever userspace application has triggered TDLS connection with any peer, driver would store this peer mac address details in its database. 2. After this driver whenever driver receives packet on direct link, it would store rssi and timestamp in peer information. 3. Whenever a packet is to be transmitted to non-AP peer in station mode, driver would check if TDLS link can be established by looking at peer RSSI information. Driver would initiate TDLS setup in such cases. 4. Periodic timer is used for updating peer information. 5. Auto TDLS peer list & timer are cleared during disconnection or driver unload. Signed-off-by: Avinash Patil <patila@marvell.com> Signed-off-by: Cathy Luo <cluo@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c6
-rw-r--r--drivers/net/wireless/mwifiex/decl.h5
-rw-r--r--drivers/net/wireless/mwifiex/init.c6
-rw-r--r--drivers/net/wireless/mwifiex/main.c7
-rw-r--r--drivers/net/wireless/mwifiex/main.h31
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c6
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c3
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c233
8 files changed, 295 insertions, 2 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index f63abfd8acd7..17f0ee02d6e7 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1806,6 +1806,10 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
1806 dev_dbg(priv->adapter->dev, 1806 dev_dbg(priv->adapter->dev,
1807 "info: associated to bssid %pM successfully\n", 1807 "info: associated to bssid %pM successfully\n",
1808 priv->cfg_bssid); 1808 priv->cfg_bssid);
1809 if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
1810 priv->adapter->auto_tdls &&
1811 priv->bss_type == MWIFIEX_BSS_TYPE_STA)
1812 mwifiex_setup_auto_tdls_timer(priv);
1809 } else { 1813 } else {
1810 dev_dbg(priv->adapter->dev, 1814 dev_dbg(priv->adapter->dev,
1811 "info: association to bssid %pM failed\n", 1815 "info: association to bssid %pM failed\n",
@@ -2677,11 +2681,13 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
2677 dev_dbg(priv->adapter->dev, 2681 dev_dbg(priv->adapter->dev,
2678 "Send TDLS Setup Request to %pM status_code=%d\n", peer, 2682 "Send TDLS Setup Request to %pM status_code=%d\n", peer,
2679 status_code); 2683 status_code);
2684 mwifiex_add_auto_tdls_peer(priv, peer);
2680 ret = mwifiex_send_tdls_data_frame(priv, peer, action_code, 2685 ret = mwifiex_send_tdls_data_frame(priv, peer, action_code,
2681 dialog_token, status_code, 2686 dialog_token, status_code,
2682 extra_ies, extra_ies_len); 2687 extra_ies, extra_ies_len);
2683 break; 2688 break;
2684 case WLAN_TDLS_SETUP_RESPONSE: 2689 case WLAN_TDLS_SETUP_RESPONSE:
2690 mwifiex_add_auto_tdls_peer(priv, peer);
2685 dev_dbg(priv->adapter->dev, 2691 dev_dbg(priv->adapter->dev,
2686 "Send TDLS Setup Response to %pM status_code=%d\n", 2692 "Send TDLS Setup Response to %pM status_code=%d\n",
2687 peer, status_code); 2693 peer, status_code);
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index f53e5b50d3d8..fc0b1ed80a6a 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -85,6 +85,11 @@
85#define MWIFIEX_TDLS_CREATE_LINK 0x02 85#define MWIFIEX_TDLS_CREATE_LINK 0x02
86#define MWIFIEX_TDLS_CONFIG_LINK 0x03 86#define MWIFIEX_TDLS_CONFIG_LINK 0x03
87 87
88#define MWIFIEX_TDLS_RSSI_HIGH 50
89#define MWIFIEX_TDLS_RSSI_LOW 55
90#define MWIFIEX_TDLS_MAX_FAIL_COUNT 4
91#define MWIFIEX_AUTO_TDLS_IDLE_TIME 10
92
88enum mwifiex_bss_type { 93enum mwifiex_bss_type {
89 MWIFIEX_BSS_TYPE_STA = 0, 94 MWIFIEX_BSS_TYPE_STA = 0,
90 MWIFIEX_BSS_TYPE_UAP = 1, 95 MWIFIEX_BSS_TYPE_UAP = 1,
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index bd740b630b31..ee512425a938 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -137,6 +137,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
137 priv->csa_expire_time = 0; 137 priv->csa_expire_time = 0;
138 priv->del_list_idx = 0; 138 priv->del_list_idx = 0;
139 priv->hs2_enabled = false; 139 priv->hs2_enabled = false;
140 priv->check_tdls_tx = false;
140 memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID); 141 memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID);
141 142
142 return mwifiex_add_bss_prio_tbl(priv); 143 return mwifiex_add_bss_prio_tbl(priv);
@@ -248,6 +249,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
248 adapter->hw_dev_mcs_support = 0; 249 adapter->hw_dev_mcs_support = 0;
249 adapter->sec_chan_offset = 0; 250 adapter->sec_chan_offset = 0;
250 adapter->adhoc_11n_enabled = false; 251 adapter->adhoc_11n_enabled = false;
252 adapter->auto_tdls = false;
251 253
252 mwifiex_wmm_init(adapter); 254 mwifiex_wmm_init(adapter);
253 255
@@ -366,6 +368,7 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
366 list_del(&priv->tx_ba_stream_tbl_ptr); 368 list_del(&priv->tx_ba_stream_tbl_ptr);
367 list_del(&priv->rx_reorder_tbl_ptr); 369 list_del(&priv->rx_reorder_tbl_ptr);
368 list_del(&priv->sta_list); 370 list_del(&priv->sta_list);
371 list_del(&priv->auto_tdls_list);
369 } 372 }
370 } 373 }
371} 374}
@@ -434,6 +437,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
434 spin_lock_init(&priv->wmm.ra_list_spinlock); 437 spin_lock_init(&priv->wmm.ra_list_spinlock);
435 spin_lock_init(&priv->curr_bcn_buf_lock); 438 spin_lock_init(&priv->curr_bcn_buf_lock);
436 spin_lock_init(&priv->sta_list_spinlock); 439 spin_lock_init(&priv->sta_list_spinlock);
440 spin_lock_init(&priv->auto_tdls_lock);
437 } 441 }
438 } 442 }
439 443
@@ -465,6 +469,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
465 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr); 469 INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
466 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); 470 INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
467 INIT_LIST_HEAD(&priv->sta_list); 471 INIT_LIST_HEAD(&priv->sta_list);
472 INIT_LIST_HEAD(&priv->auto_tdls_list);
468 skb_queue_head_init(&priv->tdls_txq); 473 skb_queue_head_init(&priv->tdls_txq);
469 474
470 spin_lock_init(&priv->tx_ba_stream_tbl_lock); 475 spin_lock_init(&priv->tx_ba_stream_tbl_lock);
@@ -645,6 +650,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
645 if (adapter->priv[i]) { 650 if (adapter->priv[i]) {
646 priv = adapter->priv[i]; 651 priv = adapter->priv[i];
647 652
653 mwifiex_clean_auto_tdls(priv);
648 mwifiex_clean_txrx(priv); 654 mwifiex_clean_txrx(priv);
649 mwifiex_delete_bss_prio_tbl(priv); 655 mwifiex_delete_bss_prio_tbl(priv);
650 } 656 }
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 2de8a6a84620..0e50120eb807 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -662,6 +662,13 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
662 */ 662 */
663 __net_timestamp(skb); 663 __net_timestamp(skb);
664 664
665 if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
666 priv->bss_type == MWIFIEX_BSS_TYPE_STA &&
667 !ether_addr_equal_unaligned(priv->cfg_bssid, skb->data)) {
668 if (priv->adapter->auto_tdls && priv->check_tdls_tx)
669 mwifiex_tdls_check_tx(priv, skb);
670 }
671
665 mwifiex_queue_tx_pkt(priv, skb); 672 mwifiex_queue_tx_pkt(priv, skb);
666 673
667 return 0; 674 return 0;
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index fa84888cf092..51a67f34c8cb 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -506,8 +506,11 @@ struct mwifiex_private {
506 struct mwifiex_wmm_desc wmm; 506 struct mwifiex_wmm_desc wmm;
507 atomic_t wmm_tx_pending[IEEE80211_NUM_ACS]; 507 atomic_t wmm_tx_pending[IEEE80211_NUM_ACS];
508 struct list_head sta_list; 508 struct list_head sta_list;
509 /* spin lock for associated station list */ 509 /* spin lock for associated station/TDLS peers list */
510 spinlock_t sta_list_spinlock; 510 spinlock_t sta_list_spinlock;
511 struct list_head auto_tdls_list;
512 /* spin lock for auto TDLS peer list */
513 spinlock_t auto_tdls_lock;
511 struct list_head tx_ba_stream_tbl_ptr; 514 struct list_head tx_ba_stream_tbl_ptr;
512 /* spin lock for tx_ba_stream_tbl_ptr queue */ 515 /* spin lock for tx_ba_stream_tbl_ptr queue */
513 spinlock_t tx_ba_stream_tbl_lock; 516 spinlock_t tx_ba_stream_tbl_lock;
@@ -572,6 +575,9 @@ struct mwifiex_private {
572 bool hs2_enabled; 575 bool hs2_enabled;
573 struct station_parameters *sta_params; 576 struct station_parameters *sta_params;
574 struct sk_buff_head tdls_txq; 577 struct sk_buff_head tdls_txq;
578 u8 check_tdls_tx;
579 struct timer_list auto_tdls_timer;
580 bool auto_tdls_timer_active;
575}; 581};
576 582
577enum mwifiex_ba_status { 583enum mwifiex_ba_status {
@@ -671,6 +677,17 @@ struct mwifiex_sta_node {
671 struct mwifiex_tdls_capab tdls_cap; 677 struct mwifiex_tdls_capab tdls_cap;
672}; 678};
673 679
680struct mwifiex_auto_tdls_peer {
681 struct list_head list;
682 u8 mac_addr[ETH_ALEN];
683 u8 tdls_status;
684 int rssi;
685 long rssi_jiffies;
686 u8 failure_count;
687 u8 do_discover;
688 u8 do_setup;
689};
690
674struct mwifiex_if_ops { 691struct mwifiex_if_ops {
675 int (*init_if) (struct mwifiex_adapter *); 692 int (*init_if) (struct mwifiex_adapter *);
676 void (*cleanup_if) (struct mwifiex_adapter *); 693 void (*cleanup_if) (struct mwifiex_adapter *);
@@ -848,6 +865,7 @@ struct mwifiex_adapter {
848 struct mwifiex_chan_stats *chan_stats; 865 struct mwifiex_chan_stats *chan_stats;
849 u32 num_in_chan_stats; 866 u32 num_in_chan_stats;
850 int survey_idx; 867 int survey_idx;
868 bool auto_tdls;
851}; 869};
852 870
853int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); 871int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -1305,6 +1323,17 @@ u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band,
1305 u32 pri_chan, u8 chan_bw); 1323 u32 pri_chan, u8 chan_bw);
1306int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter); 1324int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter);
1307 1325
1326int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb);
1327void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv);
1328void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,
1329 const u8 *mac, u8 link_status);
1330void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,
1331 u8 *mac, s8 snr, s8 nflr);
1332void mwifiex_check_auto_tdls(unsigned long context);
1333void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac);
1334void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv);
1335void mwifiex_clean_auto_tdls(struct mwifiex_private *priv);
1336
1308#ifdef CONFIG_DEBUG_FS 1337#ifdef CONFIG_DEBUG_FS
1309void mwifiex_debugfs_init(void); 1338void mwifiex_debugfs_init(void);
1310void mwifiex_debugfs_remove(void); 1339void mwifiex_debugfs_remove(void);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index 0efd6f0ffd38..204ecc8faa5b 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -55,9 +55,13 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
55 priv->scan_block = false; 55 priv->scan_block = false;
56 56
57 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && 57 if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
58 ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) 58 ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) {
59 mwifiex_disable_all_tdls_links(priv); 59 mwifiex_disable_all_tdls_links(priv);
60 60
61 if (priv->adapter->auto_tdls)
62 mwifiex_clean_auto_tdls(priv);
63 }
64
61 /* Free Tx and Rx packets, report disconnect to upper layer */ 65 /* Free Tx and Rx packets, report disconnect to upper layer */
62 mwifiex_clean_txrx(priv); 66 mwifiex_clean_txrx(priv);
63 67
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
index 9ceb1dbe34c5..c2ad3b63ae70 100644
--- a/drivers/net/wireless/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -232,6 +232,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_private *priv,
232 if (sta_ptr) 232 if (sta_ptr)
233 sta_ptr->rx_seq[local_rx_pd->priority] = 233 sta_ptr->rx_seq[local_rx_pd->priority] =
234 le16_to_cpu(local_rx_pd->seq_num); 234 le16_to_cpu(local_rx_pd->seq_num);
235 mwifiex_auto_tdls_update_peer_signal(priv, ta,
236 local_rx_pd->snr,
237 local_rx_pd->nf);
235 } 238 }
236 } else { 239 } else {
237 if (rx_pkt_type != PKT_TYPE_BAR) 240 if (rx_pkt_type != PKT_TYPE_BAR)
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
index 93a492f5fa45..22884b429be7 100644
--- a/drivers/net/wireless/mwifiex/tdls.c
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -1028,6 +1028,7 @@ mwifiex_tdls_process_disable_link(struct mwifiex_private *priv, const u8 *peer)
1028 } 1028 }
1029 1029
1030 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); 1030 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
1031 mwifiex_auto_tdls_update_peer_status(priv, peer, TDLS_NOT_SETUP);
1031 memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN); 1032 memcpy(&tdls_oper.peer_mac, peer, ETH_ALEN);
1032 tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK; 1033 tdls_oper.tdls_action = MWIFIEX_TDLS_DISABLE_LINK;
1033 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER, 1034 return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_OPER,
@@ -1072,6 +1073,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
1072 1073
1073 memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); 1074 memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq));
1074 mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); 1075 mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE);
1076 mwifiex_auto_tdls_update_peer_status(priv, peer,
1077 TDLS_SETUP_COMPLETE);
1075 } else { 1078 } else {
1076 dev_dbg(priv->adapter->dev, 1079 dev_dbg(priv->adapter->dev,
1077 "tdls: enable link %pM failed\n", peer); 1080 "tdls: enable link %pM failed\n", peer);
@@ -1085,6 +1088,8 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer)
1085 mwifiex_del_sta_entry(priv, peer); 1088 mwifiex_del_sta_entry(priv, peer);
1086 } 1089 }
1087 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN); 1090 mwifiex_restore_tdls_packets(priv, peer, TDLS_LINK_TEARDOWN);
1091 mwifiex_auto_tdls_update_peer_status(priv, peer,
1092 TDLS_NOT_SETUP);
1088 1093
1089 return -1; 1094 return -1;
1090 } 1095 }
@@ -1152,3 +1157,231 @@ void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
1152 1157
1153 mwifiex_del_all_sta_list(priv); 1158 mwifiex_del_all_sta_list(priv);
1154} 1159}
1160
1161int mwifiex_tdls_check_tx(struct mwifiex_private *priv, struct sk_buff *skb)
1162{
1163 struct mwifiex_auto_tdls_peer *peer;
1164 unsigned long flags;
1165 u8 mac[ETH_ALEN];
1166
1167 ether_addr_copy(mac, skb->data);
1168
1169 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1170 list_for_each_entry(peer, &priv->auto_tdls_list, list) {
1171 if (!memcmp(mac, peer->mac_addr, ETH_ALEN)) {
1172 if (peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&
1173 peer->tdls_status == TDLS_NOT_SETUP &&
1174 (peer->failure_count <
1175 MWIFIEX_TDLS_MAX_FAIL_COUNT)) {
1176 peer->tdls_status = TDLS_SETUP_INPROGRESS;
1177 dev_dbg(priv->adapter->dev,
1178 "setup TDLS link, peer=%pM rssi=%d\n",
1179 peer->mac_addr, peer->rssi);
1180
1181 cfg80211_tdls_oper_request(priv->netdev,
1182 peer->mac_addr,
1183 NL80211_TDLS_SETUP,
1184 0, GFP_ATOMIC);
1185 peer->do_setup = false;
1186 priv->check_tdls_tx = false;
1187 } else if (peer->failure_count <
1188 MWIFIEX_TDLS_MAX_FAIL_COUNT &&
1189 peer->do_discover) {
1190 mwifiex_send_tdls_data_frame(priv,
1191 peer->mac_addr,
1192 WLAN_TDLS_DISCOVERY_REQUEST,
1193 1, 0, NULL, 0);
1194 peer->do_discover = false;
1195 }
1196 }
1197 }
1198 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1199
1200 return 0;
1201}
1202
1203void mwifiex_flush_auto_tdls_list(struct mwifiex_private *priv)
1204{
1205 struct mwifiex_auto_tdls_peer *peer, *tmp_node;
1206 unsigned long flags;
1207
1208 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1209 list_for_each_entry_safe(peer, tmp_node, &priv->auto_tdls_list, list) {
1210 list_del(&peer->list);
1211 kfree(peer);
1212 }
1213
1214 INIT_LIST_HEAD(&priv->auto_tdls_list);
1215 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1216 priv->check_tdls_tx = false;
1217}
1218
1219void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac)
1220{
1221 struct mwifiex_auto_tdls_peer *tdls_peer;
1222 unsigned long flags;
1223
1224 if (!priv->adapter->auto_tdls)
1225 return;
1226
1227 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1228 list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
1229 if (!memcmp(tdls_peer->mac_addr, mac, ETH_ALEN)) {
1230 tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;
1231 tdls_peer->rssi_jiffies = jiffies;
1232 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1233 return;
1234 }
1235 }
1236
1237 /* create new TDLS peer */
1238 tdls_peer = kzalloc(sizeof(*tdls_peer), GFP_ATOMIC);
1239 if (tdls_peer) {
1240 ether_addr_copy(tdls_peer->mac_addr, mac);
1241 tdls_peer->tdls_status = TDLS_SETUP_INPROGRESS;
1242 tdls_peer->rssi_jiffies = jiffies;
1243 INIT_LIST_HEAD(&tdls_peer->list);
1244 list_add_tail(&tdls_peer->list, &priv->auto_tdls_list);
1245 dev_dbg(priv->adapter->dev, "Add auto TDLS peer= %pM to list\n",
1246 mac);
1247 }
1248
1249 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1250}
1251
1252void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv,
1253 const u8 *mac, u8 link_status)
1254{
1255 struct mwifiex_auto_tdls_peer *peer;
1256 unsigned long flags;
1257
1258 if (!priv->adapter->auto_tdls)
1259 return;
1260
1261 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1262 list_for_each_entry(peer, &priv->auto_tdls_list, list) {
1263 if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
1264 if ((link_status == TDLS_NOT_SETUP) &&
1265 (peer->tdls_status == TDLS_SETUP_INPROGRESS))
1266 peer->failure_count++;
1267 else if (link_status == TDLS_SETUP_COMPLETE)
1268 peer->failure_count = 0;
1269
1270 peer->tdls_status = link_status;
1271 break;
1272 }
1273 }
1274 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1275}
1276
1277void mwifiex_auto_tdls_update_peer_signal(struct mwifiex_private *priv,
1278 u8 *mac, s8 snr, s8 nflr)
1279{
1280 struct mwifiex_auto_tdls_peer *peer;
1281 unsigned long flags;
1282
1283 if (!priv->adapter->auto_tdls)
1284 return;
1285
1286 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1287 list_for_each_entry(peer, &priv->auto_tdls_list, list) {
1288 if (!memcmp(peer->mac_addr, mac, ETH_ALEN)) {
1289 peer->rssi = nflr - snr;
1290 peer->rssi_jiffies = jiffies;
1291 break;
1292 }
1293 }
1294 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1295}
1296
1297void mwifiex_check_auto_tdls(unsigned long context)
1298{
1299 struct mwifiex_private *priv = (struct mwifiex_private *)context;
1300 struct mwifiex_auto_tdls_peer *tdls_peer;
1301 unsigned long flags;
1302 u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
1303
1304 if (WARN_ON_ONCE(!priv || !priv->adapter)) {
1305 pr_err("mwifiex: %s: adapter or private structure is NULL\n",
1306 __func__);
1307 return;
1308 }
1309
1310 if (unlikely(!priv->adapter->auto_tdls))
1311 return;
1312
1313 if (!priv->auto_tdls_timer_active) {
1314 dev_dbg(priv->adapter->dev,
1315 "auto TDLS timer inactive; return");
1316 return;
1317 }
1318
1319 priv->check_tdls_tx = false;
1320
1321 if (list_empty(&priv->auto_tdls_list)) {
1322 mod_timer(&priv->auto_tdls_timer,
1323 jiffies +
1324 msecs_to_jiffies(MWIFIEX_TIMER_10S));
1325 return;
1326 }
1327
1328 spin_lock_irqsave(&priv->auto_tdls_lock, flags);
1329 list_for_each_entry(tdls_peer, &priv->auto_tdls_list, list) {
1330 if ((jiffies - tdls_peer->rssi_jiffies) >
1331 (MWIFIEX_AUTO_TDLS_IDLE_TIME * HZ)) {
1332 tdls_peer->rssi = 0;
1333 tdls_peer->do_discover = true;
1334 priv->check_tdls_tx = true;
1335 }
1336
1337 if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) ||
1338 !tdls_peer->rssi) &&
1339 tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) {
1340 tdls_peer->tdls_status = TDLS_LINK_TEARDOWN;
1341 dev_dbg(priv->adapter->dev,
1342 "teardown TDLS link,peer=%pM rssi=%d\n",
1343 tdls_peer->mac_addr, -tdls_peer->rssi);
1344 tdls_peer->do_discover = true;
1345 priv->check_tdls_tx = true;
1346 cfg80211_tdls_oper_request(priv->netdev,
1347 tdls_peer->mac_addr,
1348 NL80211_TDLS_TEARDOWN,
1349 reason, GFP_ATOMIC);
1350 } else if (tdls_peer->rssi &&
1351 tdls_peer->rssi <= MWIFIEX_TDLS_RSSI_HIGH &&
1352 tdls_peer->tdls_status == TDLS_NOT_SETUP &&
1353 tdls_peer->failure_count <
1354 MWIFIEX_TDLS_MAX_FAIL_COUNT) {
1355 priv->check_tdls_tx = true;
1356 tdls_peer->do_setup = true;
1357 dev_dbg(priv->adapter->dev,
1358 "check TDLS with peer=%pM rssi=%d\n",
1359 tdls_peer->mac_addr, -tdls_peer->rssi);
1360 }
1361 }
1362 spin_unlock_irqrestore(&priv->auto_tdls_lock, flags);
1363
1364 mod_timer(&priv->auto_tdls_timer,
1365 jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
1366}
1367
1368void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv)
1369{
1370 init_timer(&priv->auto_tdls_timer);
1371 priv->auto_tdls_timer.function = mwifiex_check_auto_tdls;
1372 priv->auto_tdls_timer.data = (unsigned long)priv;
1373 priv->auto_tdls_timer_active = true;
1374 mod_timer(&priv->auto_tdls_timer,
1375 jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
1376}
1377
1378void mwifiex_clean_auto_tdls(struct mwifiex_private *priv)
1379{
1380 if (ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) &&
1381 priv->adapter->auto_tdls &&
1382 priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
1383 priv->auto_tdls_timer_active = false;
1384 del_timer(&priv->auto_tdls_timer);
1385 mwifiex_flush_auto_tdls_list(priv);
1386 }
1387}