LOCAL_CPPFLAGS := $(wificond_cpp_flags)
LOCAL_C_INCLUDES := $(wificond_includes)
LOCAL_SRC_FILES := \
+ net/mlme_event.cpp \
net/netlink_manager.cpp \
net/netlink_utils.cpp \
net/nl80211_attribute.cpp \
#include <wifi_system/wifi.h>
#include "wificond/client_interface_binder.h"
+#include "wificond/net/mlme_event.h"
#include "wificond/net/netlink_utils.h"
#include "wificond/scanning/scan_result.h"
#include "wificond/scanning/scan_utils.h"
namespace android {
namespace wificond {
+MlmeEventHandlerImpl::MlmeEventHandlerImpl(ClientInterfaceImpl* client_interface)
+ : client_interface_(client_interface) {
+}
+
+MlmeEventHandlerImpl::~MlmeEventHandlerImpl() {
+}
+
+void MlmeEventHandlerImpl::OnConnect(unique_ptr<MlmeConnectEvent> event) {
+ if (event->GetStatusCode() == 0) {
+ client_interface_->RefreshAssociateFreq();
+ client_interface_->bssid_ = event->GetBSSID();
+ }
+}
+
+void MlmeEventHandlerImpl::OnRoam(unique_ptr<MlmeRoamEvent> event) {
+ if (event->GetStatusCode() == 0) {
+ client_interface_->RefreshAssociateFreq();
+ client_interface_->bssid_ = event->GetBSSID();
+ }
+}
+
+void MlmeEventHandlerImpl::OnAssociate(unique_ptr<MlmeAssociateEvent> event) {
+ if (event->GetStatusCode() == 0) {
+ client_interface_->RefreshAssociateFreq();
+ client_interface_->bssid_ = event->GetBSSID();
+ }
+}
+
ClientInterfaceImpl::ClientInterfaceImpl(
const std::string& interface_name,
uint32_t interface_index,
supplicant_manager_(supplicant_manager),
netlink_utils_(netlink_utils),
scan_utils_(scan_utils),
+ mlme_event_handler_(new MlmeEventHandlerImpl(this)),
binder_(new ClientInterfaceBinder(this)) {
scan_utils_->SubscribeScanResultNotification(
interface_index_,
std::bind(&ClientInterfaceImpl::OnScanResultsReady,
this,
_1, _2, _3, _4));
+ netlink_utils_->SubscribeMlmeEvent(
+ interface_index_,
+ mlme_event_handler_.get());
}
ClientInterfaceImpl::~ClientInterfaceImpl() {
binder_->NotifyImplDead();
DisableSupplicant();
scan_utils_->UnsubscribeScanResultNotification(interface_index_);
+ netlink_utils_->UnsubscribeMlmeEvent(interface_index_);
if_tool_->SetUpState(interface_name_.c_str(), false);
}
return true;
}
+bool ClientInterfaceImpl::RefreshAssociateFreq() {
+ // wpa_supplicant fetches associate frequency using the latest scan result.
+ // We should follow the same method here before we find a better solution.
+ std::vector<ScanResult> scan_results;
+ if (!scan_utils_->GetScanResult(interface_index_, &scan_results)) {
+ return false;
+ }
+ for (auto& scan_result : scan_results) {
+ if (scan_result.associated) {
+ associate_freq_ = scan_result.frequency;
+ }
+ }
+ return false;
+}
+
} // namespace wificond
} // namespace android
#include <wifi_system/supplicant_manager.h>
#include "android/net/wifi/IClientInterface.h"
+#include "wificond/net/mlme_event_handler.h"
namespace android {
namespace wificond {
class ClientInterfaceBinder;
+class ClientInterfaceImpl;
class NetlinkUtils;
class ScanUtils;
+class MlmeEventHandlerImpl : public MlmeEventHandler {
+ public:
+ MlmeEventHandlerImpl(ClientInterfaceImpl* client_interface);
+ ~MlmeEventHandlerImpl() override;
+ void OnConnect(std::unique_ptr<MlmeConnectEvent> event) override;
+ void OnRoam(std::unique_ptr<MlmeRoamEvent> event) override;
+ void OnAssociate(std::unique_ptr<MlmeAssociateEvent> event) override;
+
+ private:
+ ClientInterfaceImpl* client_interface_;
+};
+
// Holds the guts of how we control network interfaces capable of connecting to
// access points via wpa_supplicant.
//
std::vector<std::vector<uint8_t>>& ssids,
std::vector<uint32_t>& frequencies);
void OnSchedScanResultsReady(uint32_t interface_index);
+ bool RefreshAssociateFreq();
const std::string interface_name_;
const uint32_t interface_index_;
android::wifi_system::SupplicantManager* const supplicant_manager_;
NetlinkUtils* const netlink_utils_;
ScanUtils* const scan_utils_;
+ const std::unique_ptr<MlmeEventHandlerImpl> mlme_event_handler_;
const android::sp<ClientInterfaceBinder> binder_;
+ std::vector<uint8_t> bssid_;
+ uint32_t associate_freq_;
+
DISALLOW_COPY_AND_ASSIGN(ClientInterfaceImpl);
+ friend class MlmeEventHandlerImpl;
};
} // namespace wificond
--- /dev/null
+/*
+ * Copyright (C) 2016 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 "wificond/net/mlme_event.h"
+
+#include <vector>
+
+#include <linux/nl80211.h>
+
+#include <android-base/logging.h>
+
+#include "wificond/net/nl80211_packet.h"
+
+using std::unique_ptr;
+using std::vector;
+
+namespace android {
+namespace wificond {
+
+namespace {
+
+bool GetCommonFields(const NL80211Packet* packet,
+ uint32_t* if_index,
+ vector<uint8_t>* bssid) {
+ if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, if_index)) {
+ LOG(ERROR) << "Failed to get NL80211_ATTR_IFINDEX";
+ return false;
+ }
+ if (!packet->GetAttributeValue(NL80211_ATTR_MAC, bssid)) {
+ LOG(ERROR) << "Failed to get NL80211_ATTR_MAC";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+unique_ptr<MlmeAssociateEvent> MlmeAssociateEvent::InitFromPacket(
+ const NL80211Packet* packet) {
+ if (packet->GetCommand() != NL80211_CMD_ASSOCIATE) {
+ return nullptr;
+ }
+ unique_ptr<MlmeAssociateEvent> associate_event(new MlmeAssociateEvent());
+
+ if (!GetCommonFields(packet,
+ &(associate_event->interface_index_),
+ &(associate_event->bssid_))){
+ return nullptr;
+ }
+ // According to wpa_supplicant, status code of an ASSOCIATE event should be
+ // parsed from NL80211_ATTR_FRAME attribute.
+ // TODO(nywang): Parse NL80211_ATTR_FRAME 80211 management frame and get
+ // status code.
+ associate_event->status_code_ = 0;
+ return associate_event;
+}
+
+unique_ptr<MlmeConnectEvent> MlmeConnectEvent::InitFromPacket(
+ const NL80211Packet* packet) {
+ if (packet->GetCommand() != NL80211_CMD_CONNECT) {
+ return nullptr;
+ }
+ unique_ptr<MlmeConnectEvent> connect_event(new MlmeConnectEvent());
+ if (!GetCommonFields(packet,
+ &(connect_event->interface_index_),
+ &(connect_event->bssid_))){
+ return nullptr;
+ }
+
+ if (!packet->GetAttributeValue(NL80211_ATTR_STATUS_CODE,
+ &(connect_event->status_code_))) {
+ LOG(WARNING) << "Failed to get NL80211_ATTR_STATUS_CODE";
+ connect_event->status_code_ = 0;
+ }
+ return connect_event;
+}
+
+unique_ptr<MlmeRoamEvent> MlmeRoamEvent::InitFromPacket(
+ const NL80211Packet* packet) {
+ if (packet->GetCommand() != NL80211_CMD_CONNECT) {
+ return nullptr;
+ }
+ unique_ptr<MlmeRoamEvent> roam_event(new MlmeRoamEvent());
+ if (!GetCommonFields(packet,
+ &(roam_event->interface_index_),
+ &(roam_event->bssid_))){
+ return nullptr;
+ }
+
+ if (!packet->GetAttributeValue(NL80211_ATTR_STATUS_CODE,
+ &(roam_event->status_code_))) {
+ LOG(WARNING) << "Failed to get NL80211_ATTR_STATUS_CODE";
+ roam_event->status_code_ = 0;
+ }
+
+ return roam_event;
+}
+
+} // namespace wificond
+} // namespace android
--- /dev/null
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef WIFICOND_NET_MLME_EVENT_H_
+#define WIFICOND_NET_MLME_EVENT_H_
+
+#include <memory>
+#include <vector>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace wificond {
+
+class NL80211Packet;
+
+class MlmeConnectEvent {
+ public:
+ static std::unique_ptr<MlmeConnectEvent> InitFromPacket(
+ const NL80211Packet* packet);
+ // Returns the BSSID of the associated AP.
+ const std::vector<uint8_t>& GetBSSID() const { return bssid_; }
+ // Get the status code of this connect event.
+ // 0 = success, non-zero = failure.
+ // Status codes definition: IEEE 802.11-2012, 8.4.1.9, Table 8-37
+ uint16_t GetStatusCode() const { return status_code_; }
+ uint32_t GetInterfaceIndex() const { return interface_index_; }
+
+ private:
+ MlmeConnectEvent() = default;
+
+ uint32_t interface_index_;
+ std::vector<uint8_t> bssid_;
+ uint16_t status_code_;
+
+ DISALLOW_COPY_AND_ASSIGN(MlmeConnectEvent);
+};
+
+class MlmeAssociateEvent {
+ public:
+ static std::unique_ptr<MlmeAssociateEvent> InitFromPacket(
+ const NL80211Packet* packet);
+ // Returns the BSSID of the associated AP.
+ const std::vector<uint8_t>& GetBSSID() const { return bssid_; }
+ // Get the status code of this associate event.
+ // 0 = success, non-zero = failure.
+ // Status codes definition: IEEE 802.11-2012, 8.4.1.9, Table 8-37
+ uint16_t GetStatusCode() const { return status_code_; }
+ uint32_t GetInterfaceIndex() const { return interface_index_; }
+
+ private:
+ MlmeAssociateEvent() = default;
+
+ uint32_t interface_index_;
+ std::vector<uint8_t> bssid_;
+ uint16_t status_code_;
+
+ DISALLOW_COPY_AND_ASSIGN(MlmeAssociateEvent);
+};
+
+class MlmeRoamEvent {
+ public:
+ static std::unique_ptr<MlmeRoamEvent> InitFromPacket(
+ const NL80211Packet* packet);
+ // Returns the BSSID of the associated AP.
+ const std::vector<uint8_t>& GetBSSID() const { return bssid_; }
+ // Get the status code of this roam event.
+ // 0 = success, non-zero = failure.
+ // Status codes definition: IEEE 802.11-2012, 8.4.1.9, Table 8-37
+ uint16_t GetStatusCode() const { return status_code_; }
+ uint32_t GetInterfaceIndex() const { return interface_index_; }
+
+ private:
+ MlmeRoamEvent() = default;
+
+ uint32_t interface_index_;
+ std::vector<uint8_t> bssid_;
+ uint16_t status_code_;
+
+ DISALLOW_COPY_AND_ASSIGN(MlmeRoamEvent);
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_NET_MLME_EVENT_H_
--- /dev/null
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef WIFICOND_NET_MLME_EVENT_HANDLER_H_
+#define WIFICOND_NET_MLME_EVENT_HANDLER_H_
+
+#include <functional>
+#include <memory>
+
+#include <wificond/net/mlme_event.h>
+
+namespace android {
+namespace wificond {
+
+// Abstract class for handling mlme events.
+class MlmeEventHandler {
+ public:
+ virtual ~MlmeEventHandler() {}
+
+ virtual void OnConnect(std::unique_ptr<MlmeConnectEvent> event) = 0;
+ virtual void OnRoam(const std::unique_ptr<MlmeRoamEvent> event) = 0;
+ virtual void OnAssociate(std::unique_ptr<MlmeAssociateEvent> event) = 0;
+
+};
+
+} // namespace wificond
+} // namespace android
+
+#endif // WIFICOND_NET_MLME_EVENT_HANDLER_H_
#include <android-base/logging.h>
#include <utils/Timers.h>
+#include "net/mlme_event.h"
+#include "net/mlme_event_handler.h"
#include "net/nl80211_attribute.h"
#include "net/nl80211_packet.h"
// if (!SubscribeToEvents(NL80211_MULTICAST_GROUP_SCAN)) {
// return false;
// }
+ if (!SubscribeToEvents(NL80211_MULTICAST_GROUP_MLME)) {
+ return false;
+ }
started_ = true;
return true;
// available.
command == NL80211_CMD_SCAN_ABORTED) {
OnScanResultsReady(std::move(packet));
- } else if (command == NL80211_CMD_SCHED_SCAN_RESULTS) {
+ return;
+ }
+
+ if (command == NL80211_CMD_SCHED_SCAN_RESULTS) {
OnSchedScanResultsReady(std::move(packet));
+ return;
+ }
+
+
+ // Driver which supports SME uses both NL80211_CMD_AUTHENTICATE and
+ // NL80211_CMD_ASSOCIATE, otherwise it uses NL80211_CMD_CONNECT
+ // to notify a combination of authentication and association processses.
+ // Currently we monitor CONNECT/ASSOCIATE/ROAM event for up-to-date
+ // frequency and bssid.
+ // TODO(nywang): Handle other MLME events, which help us track the
+ // connection state better.
+ if (command == NL80211_CMD_CONNECT ||
+ command == NL80211_CMD_ASSOCIATE ||
+ command == NL80211_CMD_ROAM) {
+ OnMlmeEvent(std::move(packet));
+ return;
+ }
+}
+
+void NetlinkManager::OnMlmeEvent(unique_ptr<const NL80211Packet> packet) {
+ uint32_t if_index;
+
+ if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
+ LOG(ERROR) << "Failed to get interface index from a MLME event message";
+ return;
+ }
+ auto handler = on_mlme_event_handler_.find(if_index);
+ if (handler == on_mlme_event_handler_.end()) {
+ LOG(DEBUG) << "No handler for mlme event from interface"
+ << " with index: " << if_index;
+ return;
+ }
+ uint32_t command = packet->GetCommand();
+ if (command == NL80211_CMD_CONNECT) {
+ auto event = MlmeConnectEvent::InitFromPacket(packet.get());
+ if (event != nullptr) {
+ handler->second->OnConnect(std::move(event));
+ }
+ return;
+ }
+ if (command == NL80211_CMD_ASSOCIATE) {
+ auto event = MlmeAssociateEvent::InitFromPacket(packet.get());
+ if (event != nullptr) {
+ handler->second->OnAssociate(std::move(event));
+ }
+ return;
+ }
+ if (command == NL80211_CMD_ROAM) {
+ auto event = MlmeRoamEvent::InitFromPacket(packet.get());
+ if (event != nullptr) {
+ handler->second->OnRoam(std::move(event));
+ }
+ return;
}
}
on_scan_result_ready_handler_.erase(interface_index);
}
+void NetlinkManager::SubscribeMlmeEvent(uint32_t interface_index,
+ MlmeEventHandler* handler) {
+ on_mlme_event_handler_[interface_index] = handler;
+}
+
+void NetlinkManager::UnsubscribeMlmeEvent(uint32_t interface_index) {
+ on_mlme_event_handler_.erase(interface_index);
+}
+
void NetlinkManager::SubscribeSchedScanResultNotification(
uint32_t interface_index,
OnSchedScanResultsReadyHandler handler) {
namespace android {
namespace wificond {
+class MlmeEventHandler;
class NL80211Packet;
// Encapsulates all the different things we know about a specific message
// interface with index |interface_index|.
virtual void UnsubscribeScanResultNotification(uint32_t interface_index);
+ // Sign up to be notified when there is MLME event.
+ // Only one handler can be registered per interface index.
+ // New handler will replace the registered handler if they are for the
+ // same interface index.
+ // NetlinkManager is not going to take ownership of this pointer, and that it
+ // is the caller's responsibility to make sure that the object exists for the
+ // duration of the subscription.
+ virtual void SubscribeMlmeEvent(uint32_t interface_index,
+ MlmeEventHandler* handler);
+
+ // Cancel the sign-up of receiving MLME event notification
+ // from interface with index |interface_index|.
+ virtual void UnsubscribeMlmeEvent(uint32_t interface_index);
+
// Sign up to be notified when new scan results are available.
// |handler| will be called when the kernel signals to wificond that a
// scheduled scan has been completed on the given |interface_index|.
bool DiscoverFamilyId();
bool SendMessageInternal(const NL80211Packet& packet, int fd);
void BroadcastHandler(std::unique_ptr<const NL80211Packet> packet);
+ void OnMlmeEvent(std::unique_ptr<const NL80211Packet> packet);
void OnScanResultsReady(std::unique_ptr<const NL80211Packet> packet);
void OnSchedScanResultsReady(std::unique_ptr<const NL80211Packet> packet);
std::map<uint32_t, OnSchedScanResultsReadyHandler>
on_sched_scan_result_ready_handler_;
+ std::map<uint32_t, MlmeEventHandler*> on_mlme_event_handler_;
+
// Mapping from family name to family id, and group name to group id.
std::map<std::string, MessageType> message_types_;
#include <android-base/logging.h>
+#include "wificond/net/mlme_event_handler.h"
#include "wificond/net/netlink_manager.h"
#include "wificond/net/nl80211_packet.h"
return true;
}
+void NetlinkUtils::SubscribeMlmeEvent(uint32_t interface_index,
+ MlmeEventHandler* handler) {
+ netlink_manager_->SubscribeMlmeEvent(interface_index, handler);
+}
+
+void NetlinkUtils::UnsubscribeMlmeEvent(uint32_t interface_index) {
+ netlink_manager_->UnsubscribeMlmeEvent(interface_index);
+}
+
} // namespace wificond
} // namespace android
// We will add them once we find them useful.
};
+class MlmeEventHandler;
class NetlinkManager;
class NL80211Packet;
const std::vector<uint8_t>& mac_address,
StationInfo* out_station_info);
+ // Sign up to be notified when there is MLME event.
+ // Only one handler can be registered per interface index.
+ // New handler will replace the registered handler if they are for the
+ // same interface index.
+ // NetlinkUtils is not going to take ownership of this pointer, and that it
+ // is the caller's responsibility to make sure that the object exists for the
+ // duration of the subscription.
+ virtual void SubscribeMlmeEvent(uint32_t interface_index,
+ MlmeEventHandler* handler);
+
+ // Cancel the sign-up of receiving MLME event notification
+ // from interface with index |interface_index|.
+ virtual void UnsubscribeMlmeEvent(uint32_t interface_index);
+
private:
bool ParseBandInfo(const NL80211Packet* const packet,
BandInfo* out_band_info);