//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "shill/wifi/tdls_manager.h"
#include <base/bind.h>
#if defined(__ANDROID__)
#include <dbus/service_constants.h>
#else
#include <chromeos/dbus/service_constants.h>
#endif // __ANDROID__
#include "shill/error.h"
#include "shill/event_dispatcher.h"
#include "shill/logging.h"
#include "shill/supplicant/supplicant_interface_proxy_interface.h"
#include "shill/supplicant/wpa_supplicant.h"
using base::Bind;
using std::string;
namespace shill {
namespace Logging {
static auto kModuleLogScope = ScopeLogger::kWiFi;
static string ObjectID(const TDLSManager* c) {
return "(" + c->interface_name() + "-tdlsmanager)";
}
}
const int TDLSManager::kPeerDiscoveryCleanupTimeoutSeconds = 30;
TDLSManager::TDLSManager(
EventDispatcher* dispatcher,
SupplicantInterfaceProxyInterface* supplicant_interface_proxy,
const string& interface_name)
: dispatcher_(dispatcher),
supplicant_interface_proxy_(supplicant_interface_proxy),
interface_name_(interface_name) {}
TDLSManager::~TDLSManager() {}
string TDLSManager::PerformOperation(const string& peer_mac_address,
const string& operation,
Error* error) {
CHECK(supplicant_interface_proxy_);
SLOG(this, 2) << "Processing TDLS command: " << operation
<< " for peer " << peer_mac_address;
bool success = false;
if (operation == kTDLSDiscoverOperation) {
success = DiscoverPeer(peer_mac_address);
} else if (operation == kTDLSSetupOperation) {
success = SetupPeer(peer_mac_address);
} else if (operation == kTDLSStatusOperation) {
string supplicant_status = PeerStatus(peer_mac_address);
SLOG(this, 2) << "TDLS status returned: " << supplicant_status;
if (!supplicant_status.empty()) {
if (supplicant_status == WPASupplicant::kTDLSStateConnected) {
return kTDLSConnectedState;
} else if (supplicant_status == WPASupplicant::kTDLSStateDisabled) {
return kTDLSDisabledState;
} else if (supplicant_status ==
WPASupplicant::kTDLSStatePeerDoesNotExist) {
if (CheckDiscoveryState(peer_mac_address) ==
PeerDiscoveryState::kResponseReceived) {
return kTDLSDisconnectedState;
} else {
return kTDLSNonexistentState;
}
} else if (supplicant_status ==
WPASupplicant::kTDLSStatePeerNotConnected) {
return kTDLSDisconnectedState;
} else {
return kTDLSUnknownState;
}
}
} else if (operation == kTDLSTeardownOperation) {
success = TearDownPeer(peer_mac_address);
} else {
error->Populate(Error::kInvalidArguments, "Unknown operation");
return "";
}
if (!success) {
Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed,
"TDLS operation failed");
}
return "";
}
void TDLSManager::OnDiscoverResponseReceived(const string& peer_mac_address) {
if (CheckDiscoveryState(peer_mac_address) ==
PeerDiscoveryState::kRequestSent) {
peer_discovery_state_[peer_mac_address] =
PeerDiscoveryState::kResponseReceived;
}
}
bool TDLSManager::DiscoverPeer(const string& peer_mac_address) {
if (!supplicant_interface_proxy_->TDLSDiscover(peer_mac_address)) {
LOG(ERROR) << "Failed to perform TDLS discover";
return false;
}
peer_discovery_state_[peer_mac_address] = PeerDiscoveryState::kRequestSent;
StartPeerDiscoveryCleanupTimer();
return true;
}
bool TDLSManager::SetupPeer(const string& peer_mac_address) {
if (!supplicant_interface_proxy_->TDLSSetup(peer_mac_address)) {
LOG(ERROR) << "Failed to perform TDLS setup";
return false;
}
return true;
}
bool TDLSManager::TearDownPeer(const string& peer_mac_address) {
if (!supplicant_interface_proxy_->TDLSTeardown(peer_mac_address)) {
LOG(ERROR) << "Failed to perform TDLS teardown";
return false;
}
return true;
}
string TDLSManager::PeerStatus(const string& peer_mac_address) {
string status;
if (!supplicant_interface_proxy_->TDLSStatus(peer_mac_address, &status)) {
LOG(ERROR) << "Failed to perform TDLS status";
return "";
}
return status;
}
void TDLSManager::StartPeerDiscoveryCleanupTimer() {
if (!peer_discovery_cleanup_callback_.IsCancelled()) {
LOG(INFO) << __func__ << " TDLS cleanup timer restarted.";
} else {
LOG(INFO) << __func__ << " TDLS cleanup timer started.";
}
peer_discovery_cleanup_callback_.Reset(
Bind(&TDLSManager::PeerDiscoveryCleanup, base::Unretained(this)));
dispatcher_->PostDelayedTask(peer_discovery_cleanup_callback_.callback(),
kPeerDiscoveryCleanupTimeoutSeconds * 1000);
}
void TDLSManager::PeerDiscoveryCleanup() {
LOG(INFO) << __func__ << " TDLS peer discovery map cleared.";
peer_discovery_state_.clear();
}
TDLSManager::PeerDiscoveryState TDLSManager::CheckDiscoveryState(
const string& peer_mac_address) {
auto iter = peer_discovery_state_.find(peer_mac_address);
if (iter == peer_discovery_state_.end()) {
return PeerDiscoveryState::kNone;
}
return iter->second;
}
} // namespace shill.