1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2015 The Android Open Source Project 3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License"); 5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License. 6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at 7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// http://www.apache.org/licenses/LICENSE-2.0 9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software 11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS, 12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and 14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License. 15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 1665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 1765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include "shill/dbus/chromeos_dhcpcd_listener.h" 1865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 1965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include <string.h> 2065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 2165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include <base/bind.h> 2265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include <base/callback.h> 2365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include <base/strings/stringprintf.h> 2403e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko#include <brillo/dbus/dbus_method_invoker.h> 2565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include <dbus/util.h> 2665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 2765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include "shill/dhcp/dhcp_config.h" 2865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include "shill/dhcp/dhcp_provider.h" 2965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include "shill/event_dispatcher.h" 3065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu#include "shill/logging.h" 3165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 3265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiuusing std::string; 3365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 3465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiunamespace shill { 3565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 3665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiunamespace Logging { 3765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiustatic auto kModuleLogScope = ScopeLogger::kDHCP; 3865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiustatic string ObjectID(ChromeosDHCPCDListener* d) { 3965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu return "(dhcpcd_listener)"; 4065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 4165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 4265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 4365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiuconst char ChromeosDHCPCDListener::kDBusInterfaceName[] = "org.chromium.dhcpcd"; 4465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiuconst char ChromeosDHCPCDListener::kSignalEvent[] = "Event"; 4565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiuconst char ChromeosDHCPCDListener::kSignalStatusChanged[] = "StatusChanged"; 4665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 4765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter QiuChromeosDHCPCDListener::ChromeosDHCPCDListener( 4865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu const scoped_refptr<dbus::Bus>& bus, 4965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu EventDispatcher* dispatcher, 5065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu DHCPProvider* provider) 5165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu : bus_(bus), 5265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dispatcher_(dispatcher), 5365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu provider_(provider), 5465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu match_rule_(base::StringPrintf("type='signal', interface='%s'", 5565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu kDBusInterfaceName)) { 5665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu bus_->AssertOnDBusThread(); 5765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu CHECK(bus_->SetUpAsyncOperations()); 5865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (!bus_->is_connected()) { 5965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu LOG(FATAL) << "DBus isn't connected."; 6065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 6165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 6265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // Register filter function to the bus. It will be called when incoming 6365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // messages are received. 6465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu bus_->AddFilterFunction(&ChromeosDHCPCDListener::HandleMessageThunk, this); 6565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 6665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // Add match rule to the bus. 6765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dbus::ScopedDBusError error; 6865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu bus_->AddMatch(match_rule_, error.get()); 6965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (error.is_set()) { 7065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu LOG(FATAL) << "Failed to add match rule: " << error.name() << " " 7165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu << error.message(); 7265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 7365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 7465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 7565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter QiuChromeosDHCPCDListener::~ChromeosDHCPCDListener() { 7665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu bus_->RemoveFilterFunction(&ChromeosDHCPCDListener::HandleMessageThunk, this); 7765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dbus::ScopedDBusError error; 7865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu bus_->RemoveMatch(match_rule_, error.get()); 7965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (error.is_set()) { 8065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu LOG(FATAL) << "Failed to remove match rule: " << error.name() << " " 8165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu << error.message(); 8265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 8365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 8465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 8565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu// static. 8665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter QiuDBusHandlerResult ChromeosDHCPCDListener::HandleMessageThunk( 8765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu DBusConnection* connection, DBusMessage* raw_message, void* user_data) { 8865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu ChromeosDHCPCDListener* self = 8965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu static_cast<ChromeosDHCPCDListener*>(user_data); 9065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu return self->HandleMessage(connection, raw_message); 9165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 9265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 9365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter QiuDBusHandlerResult ChromeosDHCPCDListener::HandleMessage( 9465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu DBusConnection* connection, DBusMessage* raw_message) { 9565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu bus_->AssertOnDBusThread(); 9665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 9765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // Only interested in signal message. 9865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (dbus_message_get_type(raw_message) != DBUS_MESSAGE_TYPE_SIGNAL) { 9965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 10065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 10165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 10265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // raw_message will be unrefed in Signal's parent class's (dbus::Message) 10365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // destructor. Increment the reference so we can use it in Signal. 10465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dbus_message_ref(raw_message); 10565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu std::unique_ptr<dbus::Signal> signal( 10665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dbus::Signal::FromRawMessage(raw_message)); 10765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 10865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // Verify the signal comes from the interface that we interested in. 10965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (signal->GetInterface() != kDBusInterfaceName) { 11065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 11165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 11265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 11365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu string sender = signal->GetSender(); 11465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu string member_name = signal->GetMember(); 11565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dbus::MessageReader reader(signal.get()); 11665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (member_name == kSignalEvent) { 11765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu uint32_t pid; 11865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu string reason; 11903e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko brillo::VariantDictionary configurations; 12065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // ExtracMessageParameters will log the error if it failed. 12103e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko if (brillo::dbus_utils::ExtractMessageParameters(&reader, 12203e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko nullptr, 12303e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko &pid, 12403e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko &reason, 12503e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko &configurations)) { 12665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dispatcher_->PostTask( 12765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu base::Bind(&ChromeosDHCPCDListener::EventSignal, 12865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu weak_factory_.GetWeakPtr(), 12965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu sender, pid, reason, configurations)); 13065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 13165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } else if (member_name == kSignalStatusChanged) { 13265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu uint32_t pid; 13365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu string status; 13465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu // ExtracMessageParameters will log the error if it failed. 13503e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko if (brillo::dbus_utils::ExtractMessageParameters(&reader, 13603e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko nullptr, 13703e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko &pid, 13803e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko &status)) { 13965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu dispatcher_->PostTask( 14065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu base::Bind(&ChromeosDHCPCDListener::StatusChangedSignal, 14165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu weak_factory_.GetWeakPtr(), 14265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu sender, pid, status)); 14365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 14465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } else { 14565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu LOG(INFO) << "Ignore signal: " << member_name; 14665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 14765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 14865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu return DBUS_HANDLER_RESULT_HANDLED; 14965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 15065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 15165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiuvoid ChromeosDHCPCDListener::EventSignal( 15265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu const string& sender, 15365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu uint32_t pid, 15465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu const string& reason, 15503e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko const brillo::VariantDictionary& configuration) { 15665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu DHCPConfigRefPtr config = provider_->GetConfig(pid); 15765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (!config.get()) { 15865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (provider_->IsRecentlyUnbound(pid)) { 15965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu SLOG(nullptr, 3) 16065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu << __func__ << ": ignoring message from recently unbound PID " << pid; 16165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } else { 16265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu LOG(ERROR) << "Unknown DHCP client PID " << pid; 16365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 16465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu return; 16565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 16665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu config->InitProxy(sender); 16765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu KeyValueStore configuration_store; 16865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu KeyValueStore::ConvertFromVariantDictionary(configuration, 16965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu &configuration_store); 17065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu config->ProcessEventSignal(reason, configuration_store); 17165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 17265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 17365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiuvoid ChromeosDHCPCDListener::StatusChangedSignal(const string& sender, 17465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu uint32_t pid, 17565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu const string& status) { 17665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu DHCPConfigRefPtr config = provider_->GetConfig(pid); 17765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (!config.get()) { 17865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu if (provider_->IsRecentlyUnbound(pid)) { 17965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu SLOG(nullptr, 3) 18065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu << __func__ << ": ignoring message from recently unbound PID " << pid; 18165a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } else { 18265a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu LOG(ERROR) << "Unknown DHCP client PID " << pid; 18365a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 18465a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu return; 18565a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu } 18665a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu config->InitProxy(sender); 18765a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu config->ProcessStatusChangeSignal(status); 18865a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} 18965a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu 19065a049b4b284b5c189e0b6f901b448edd6c3d86dPeter Qiu} // namespace shill 191