// // Copyright (C) 2012 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/net/netlink_manager.h" #include <errno.h> #include <sys/select.h> #include <sys/time.h> #include <list> #include <map> #include <queue> #include <base/location.h> #include <base/logging.h> #include <base/memory/weak_ptr.h> #include <base/message_loop/message_loop.h> #include <base/stl_util.h> #include "shill/net/attribute_list.h" #include "shill/net/generic_netlink_message.h" #include "shill/net/io_handler.h" #include "shill/net/netlink_message.h" #include "shill/net/netlink_packet.h" #include "shill/net/nl80211_message.h" #include "shill/net/shill_time.h" #include "shill/net/sockets.h" using base::Bind; using base::LazyInstance; using base::MessageLoop; using std::list; using std::map; using std::string; namespace shill { namespace { LazyInstance<NetlinkManager> g_netlink_manager = LAZY_INSTANCE_INITIALIZER; } // namespace const char NetlinkManager::kEventTypeConfig[] = "config"; const char NetlinkManager::kEventTypeScan[] = "scan"; const char NetlinkManager::kEventTypeRegulatory[] = "regulatory"; const char NetlinkManager::kEventTypeMlme[] = "mlme"; const long NetlinkManager::kMaximumNewFamilyWaitSeconds = 1; // NOLINT const long NetlinkManager::kMaximumNewFamilyWaitMicroSeconds = 0; // NOLINT const long NetlinkManager::kResponseTimeoutSeconds = 5; // NOLINT const long NetlinkManager::kResponseTimeoutMicroSeconds = 0; // NOLINT const long NetlinkManager::kPendingDumpTimeoutMilliseconds = 500; // NOLINT const long NetlinkManager::kNlMessageRetryDelayMilliseconds = 300; // NOLINT const int NetlinkManager::kMaxNlMessageRetries = 1; // NOLINT NetlinkManager::NetlinkResponseHandler::NetlinkResponseHandler( const NetlinkManager::NetlinkAckHandler& ack_handler, const NetlinkManager::NetlinkAuxilliaryMessageHandler& error_handler) : ack_handler_(ack_handler), error_handler_(error_handler) {} NetlinkManager::NetlinkResponseHandler::~NetlinkResponseHandler() {} void NetlinkManager::NetlinkResponseHandler::HandleError( AuxilliaryMessageType type, const NetlinkMessage* netlink_message) const { if (!error_handler_.is_null()) error_handler_.Run(type, netlink_message); } bool NetlinkManager::NetlinkResponseHandler::HandleAck() const { if (!ack_handler_.is_null()) { // Default behavior is not to remove callbacks. In the case where the // callback is not successfully invoked, this is safe as it does not // prevent any further responses from behind handled. bool remove_callbacks = false; ack_handler_.Run(&remove_callbacks); // If there are no other handlers other than the Ack handler, then force // the callback to be removed after handling the Ack. return remove_callbacks || error_handler_.is_null(); } else { // If there is no Ack handler, do not delete registered callbacks // for this function because we are not explicitly told to do so. return false; } } class ControlResponseHandler : public NetlinkManager::NetlinkResponseHandler { public: ControlResponseHandler( const NetlinkManager::NetlinkAckHandler& ack_handler, const NetlinkManager::NetlinkAuxilliaryMessageHandler& error_handler, const NetlinkManager::ControlNetlinkMessageHandler& handler) : NetlinkManager::NetlinkResponseHandler(ack_handler, error_handler), handler_(handler) {} bool HandleMessage(const NetlinkMessage& netlink_message) const override { if (netlink_message.message_type() != ControlNetlinkMessage::GetMessageType()) { LOG(ERROR) << "Message is type " << netlink_message.message_type() << ", not " << ControlNetlinkMessage::GetMessageType() << " (Control)."; return false; } if (!handler_.is_null()) { const ControlNetlinkMessage* message = static_cast<const ControlNetlinkMessage*>(&netlink_message); handler_.Run(*message); } return true; } bool HandleAck() const override { if (handler_.is_null()) { return NetlinkManager::NetlinkResponseHandler::HandleAck(); } else { bool remove_callbacks = false; NetlinkManager::NetlinkResponseHandler::ack_handler_.Run( &remove_callbacks); return remove_callbacks; } } private: NetlinkManager::ControlNetlinkMessageHandler handler_; DISALLOW_COPY_AND_ASSIGN(ControlResponseHandler); }; class Nl80211ResponseHandler : public NetlinkManager::NetlinkResponseHandler { public: Nl80211ResponseHandler( const NetlinkManager::NetlinkAckHandler& ack_handler, const NetlinkManager::NetlinkAuxilliaryMessageHandler& error_handler, const NetlinkManager::Nl80211MessageHandler& handler) : NetlinkManager::NetlinkResponseHandler(ack_handler, error_handler), handler_(handler) {} bool HandleMessage(const NetlinkMessage& netlink_message) const override { if (netlink_message.message_type() != Nl80211Message::GetMessageType()) { LOG(ERROR) << "Message is type " << netlink_message.message_type() << ", not " << Nl80211Message::GetMessageType() << " (Nl80211)."; return false; } if (!handler_.is_null()) { const Nl80211Message* message = static_cast<const Nl80211Message*>(&netlink_message); handler_.Run(*message); } return true; } bool HandleAck() const override { if (handler_.is_null()) { return NetlinkManager::NetlinkResponseHandler::HandleAck(); } else { bool remove_callbacks = false; NetlinkManager::NetlinkResponseHandler::ack_handler_.Run( &remove_callbacks); return remove_callbacks; } } private: NetlinkManager::Nl80211MessageHandler handler_; DISALLOW_COPY_AND_ASSIGN(Nl80211ResponseHandler); }; NetlinkManager::MessageType::MessageType() : family_id(NetlinkMessage::kIllegalMessageType) {} NetlinkManager::NetlinkManager() : weak_ptr_factory_(this), dispatcher_callback_(Bind(&NetlinkManager::OnRawNlMessageReceived, weak_ptr_factory_.GetWeakPtr())), time_(Time::GetInstance()), io_handler_factory_( IOHandlerFactoryContainer::GetInstance()->GetIOHandlerFactory()), dump_pending_(false) {} NetlinkManager::~NetlinkManager() {} NetlinkManager* NetlinkManager::GetInstance() { return g_netlink_manager.Pointer(); } void NetlinkManager::Reset(bool full) { ClearBroadcastHandlers(); message_handlers_.clear(); message_types_.clear(); while (!pending_messages_.empty()) { pending_messages_.pop(); } pending_dump_timeout_callback_.Cancel(); resend_dump_message_callback_.Cancel(); dump_pending_ = false; if (full) { sock_.reset(); } } void NetlinkManager::OnNewFamilyMessage(const ControlNetlinkMessage& message) { uint16_t family_id; string family_name; if (!message.const_attributes()->GetU16AttributeValue(CTRL_ATTR_FAMILY_ID, &family_id)) { LOG(ERROR) << __func__ << ": Couldn't get family_id attribute"; return; } if (!message.const_attributes()->GetStringAttributeValue( CTRL_ATTR_FAMILY_NAME, &family_name)) { LOG(ERROR) << __func__ << ": Couldn't get family_name attribute"; return; } VLOG(3) << "Socket family '" << family_name << "' has id=" << family_id; // Extract the available multicast groups from the message. AttributeListConstRefPtr multicast_groups; if (message.const_attributes()->ConstGetNestedAttributeList( CTRL_ATTR_MCAST_GROUPS, &multicast_groups)) { AttributeListConstRefPtr current_group; for (int i = 1; multicast_groups->ConstGetNestedAttributeList(i, ¤t_group); ++i) { string group_name; uint32_t group_id; if (!current_group->GetStringAttributeValue(CTRL_ATTR_MCAST_GRP_NAME, &group_name)) { LOG(WARNING) << "Expected CTRL_ATTR_MCAST_GRP_NAME, found none"; continue; } if (!current_group->GetU32AttributeValue(CTRL_ATTR_MCAST_GRP_ID, &group_id)) { LOG(WARNING) << "Expected CTRL_ATTR_MCAST_GRP_ID, found none"; continue; } VLOG(3) << " Adding group '" << group_name << "' = " << group_id; message_types_[family_name].groups[group_name] = group_id; } } message_types_[family_name].family_id = family_id; } // static void NetlinkManager::OnNetlinkMessageError(AuxilliaryMessageType type, const NetlinkMessage* raw_message) { switch (type) { case kErrorFromKernel: if (!raw_message) { LOG(ERROR) << "Unknown error from kernel."; break; } if (raw_message->message_type() == ErrorAckMessage::GetMessageType()) { const ErrorAckMessage* error_ack_message = static_cast<const ErrorAckMessage*>(raw_message); // error_ack_message->error() should be non-zero (i.e. not an ACK), // since ACKs would be routed to a NetlinkAckHandler in // NetlinkManager::OnNlMessageReceived. LOG(ERROR) << __func__ << ": Message (seq: " << error_ack_message->sequence_number() << ") failed: " << error_ack_message->ToString(); } break; case kUnexpectedResponseType: LOG(ERROR) << "Message not handled by regular message handler:"; if (raw_message) { raw_message->Print(0, 0); } break; case kTimeoutWaitingForResponse: LOG(WARNING) << "Timeout waiting for response"; break; default: LOG(ERROR) << "Unexpected auxilliary message type: " << type; break; } } bool NetlinkManager::Init() { // Install message factory for control class of messages, which has // statically-known message type. message_factory_.AddFactoryMethod( ControlNetlinkMessage::kMessageType, Bind(&ControlNetlinkMessage::CreateMessage)); if (!sock_) { sock_.reset(new NetlinkSocket); if (!sock_) { LOG(ERROR) << "No memory"; return false; } if (!sock_->Init()) { return false; } } return true; } void NetlinkManager::Start() { // Create an IO handler for receiving messages on the netlink socket. // IO handler will be installed to the current message loop. dispatcher_handler_.reset(io_handler_factory_->CreateIOInputHandler( file_descriptor(), dispatcher_callback_, Bind(&NetlinkManager::OnReadError, weak_ptr_factory_.GetWeakPtr()))); } int NetlinkManager::file_descriptor() const { return (sock_ ? sock_->file_descriptor() : Sockets::kInvalidFileDescriptor); } uint16_t NetlinkManager::GetFamily(const string& name, const NetlinkMessageFactory::FactoryMethod& message_factory) { MessageType& message_type = message_types_[name]; if (message_type.family_id != NetlinkMessage::kIllegalMessageType) { return message_type.family_id; } if (!sock_) { LOG(FATAL) << "Must call |Init| before this method."; return false; } GetFamilyMessage msg; if (!msg.attributes()->SetStringAttributeValue(CTRL_ATTR_FAMILY_NAME, name)) { LOG(ERROR) << "Couldn't set string attribute"; return false; } SendControlMessage(&msg, Bind(&NetlinkManager::OnNewFamilyMessage, weak_ptr_factory_.GetWeakPtr()), Bind(&NetlinkManager::OnAckDoNothing), Bind(&NetlinkManager::OnNetlinkMessageError)); // Wait for a response. The code absolutely needs family_ids for its // message types so we do a synchronous wait. It's OK to do this because // a) libnl does a synchronous wait (so there's prior art), b) waiting // asynchronously would add significant and unnecessary complexity to the // code that deals with pending messages that could, potentially, be waiting // for a message type, and c) it really doesn't take very long for the // GETFAMILY / NEWFAMILY transaction to transpire (this transaction was timed // over 20 times and found a maximum duration of 11.1 microseconds and an // average of 4.0 microseconds). struct timeval now, end_time; struct timeval maximum_wait_duration = {kMaximumNewFamilyWaitSeconds, kMaximumNewFamilyWaitMicroSeconds}; time_->GetTimeMonotonic(&now); timeradd(&now, &maximum_wait_duration, &end_time); do { // Wait with timeout for a message from the netlink socket. fd_set read_fds; FD_ZERO(&read_fds); int socket = file_descriptor(); if (socket >= FD_SETSIZE) LOG(FATAL) << "Invalid file_descriptor."; FD_SET(socket, &read_fds); struct timeval wait_duration; timersub(&end_time, &now, &wait_duration); int result = sock_->sockets()->Select(file_descriptor() + 1, &read_fds, nullptr, nullptr, &wait_duration); if (result < 0) { PLOG(ERROR) << "Select failed"; return NetlinkMessage::kIllegalMessageType; } if (result == 0) { LOG(WARNING) << "Timed out waiting for family_id for family '" << name << "'."; return NetlinkMessage::kIllegalMessageType; } // Read and process any messages. ByteString received; sock_->RecvMessage(&received); InputData input_data(received.GetData(), received.GetLength()); OnRawNlMessageReceived(&input_data); if (message_type.family_id != NetlinkMessage::kIllegalMessageType) { uint16_t family_id = message_type.family_id; if (family_id != NetlinkMessage::kIllegalMessageType) { message_factory_.AddFactoryMethod(family_id, message_factory); } return message_type.family_id; } time_->GetTimeMonotonic(&now); } while (timercmp(&now, &end_time, <)); LOG(ERROR) << "Timed out waiting for family_id for family '" << name << "'."; return NetlinkMessage::kIllegalMessageType; } bool NetlinkManager::AddBroadcastHandler(const NetlinkMessageHandler& handler) { if (FindBroadcastHandler(handler)) { LOG(WARNING) << "Trying to re-add a handler"; return false; // Should only be one copy in the list. } if (handler.is_null()) { LOG(WARNING) << "Trying to add a NULL handler"; return false; } // And add the handler to the list. VLOG(3) << "NetlinkManager::" << __func__ << " - adding handler"; broadcast_handlers_.push_back(handler); return true; } bool NetlinkManager::RemoveBroadcastHandler( const NetlinkMessageHandler& handler) { list<NetlinkMessageHandler>::iterator i; for (i = broadcast_handlers_.begin(); i != broadcast_handlers_.end(); ++i) { if ((*i).Equals(handler)) { broadcast_handlers_.erase(i); // Should only be one copy in the list so we don't have to continue // looking for another one. return true; } } LOG(WARNING) << "NetlinkMessageHandler not found."; return false; } bool NetlinkManager::FindBroadcastHandler(const NetlinkMessageHandler& handler) const { for (const auto& broadcast_handler : broadcast_handlers_) { if (broadcast_handler.Equals(handler)) { return true; } } return false; } void NetlinkManager::ClearBroadcastHandlers() { broadcast_handlers_.clear(); } bool NetlinkManager::SendControlMessage( ControlNetlinkMessage* message, const ControlNetlinkMessageHandler& message_handler, const NetlinkAckHandler& ack_handler, const NetlinkAuxilliaryMessageHandler& error_handler) { return SendOrPostMessage(message, new ControlResponseHandler(ack_handler, error_handler, message_handler)); } bool NetlinkManager::SendNl80211Message( Nl80211Message* message, const Nl80211MessageHandler& message_handler, const NetlinkAckHandler& ack_handler, const NetlinkAuxilliaryMessageHandler& error_handler) { return SendOrPostMessage(message, new Nl80211ResponseHandler(ack_handler, error_handler, message_handler)); } bool NetlinkManager::SendOrPostMessage( NetlinkMessage* message, NetlinkManager::NetlinkResponseHandler* response_handler) { if (!message) { LOG(ERROR) << "Message is NULL."; return false; } const uint32_t sequence_number = this->GetSequenceNumber(); const bool is_dump_msg = message->flags() & NLM_F_DUMP; NetlinkPendingMessage pending_message( sequence_number, is_dump_msg, message->Encode(sequence_number), NetlinkResponseHandlerRefPtr(response_handler)); // TODO(samueltan): print this debug message above the actual call to // NetlinkSocket::SendMessage in NetlinkManager::SendMessageInternal. VLOG(5) << "NL Message " << pending_message.sequence_number << " to send (" << pending_message.message_string.GetLength() << " bytes) ===>"; message->Print(6, 7); NetlinkMessage::PrintBytes(8, pending_message.message_string.GetConstData(), pending_message.message_string.GetLength()); if (is_dump_msg) { pending_messages_.push(pending_message); if (IsDumpPending()) { VLOG(5) << "Dump pending -- will send message after dump is complete"; return true; } } return RegisterHandlersAndSendMessage(pending_message); } bool NetlinkManager::RegisterHandlersAndSendMessage( const NetlinkPendingMessage& pending_message) { // Clean out timed-out message handlers. The list of outstanding messages // should be small so the time wasted by looking through all of them should // be small. struct timeval now; time_->GetTimeMonotonic(&now); map<uint32_t, NetlinkResponseHandlerRefPtr>::iterator handler_it = message_handlers_.begin(); while (handler_it != message_handlers_.end()) { if (timercmp(&now, &handler_it->second->delete_after(), >)) { // A timeout isn't always unexpected so this is not a warning. VLOG(3) << "Removing timed-out handler for sequence number " << handler_it->first; handler_it->second->HandleError(kTimeoutWaitingForResponse, nullptr); handler_it = message_handlers_.erase(handler_it); } else { ++handler_it; } } // Register handlers for replies to this message. if (!pending_message.handler) { VLOG(3) << "Handler for message was null."; } else if (ContainsKey(message_handlers_, pending_message.sequence_number)) { LOG(ERROR) << "A handler already existed for sequence: " << pending_message.sequence_number; return false; } else { struct timeval response_timeout = {kResponseTimeoutSeconds, kResponseTimeoutMicroSeconds}; struct timeval delete_after; timeradd(&now, &response_timeout, &delete_after); pending_message.handler->set_delete_after(delete_after); message_handlers_[pending_message.sequence_number] = pending_message.handler; } return SendMessageInternal(pending_message); } bool NetlinkManager::SendMessageInternal( const NetlinkPendingMessage& pending_message) { VLOG(5) << "Sending NL message " << pending_message.sequence_number; if (!sock_->SendMessage(pending_message.message_string)) { LOG(ERROR) << "Failed to send Netlink message."; return false; } if (pending_message.is_dump_request) { VLOG(5) << "Waiting for replies to NL dump message " << pending_message.sequence_number; dump_pending_ = true; pending_dump_timeout_callback_.Reset(Bind( &NetlinkManager::OnPendingDumpTimeout, weak_ptr_factory_.GetWeakPtr())); MessageLoop::current()->PostDelayedTask( FROM_HERE, pending_dump_timeout_callback_.callback(), base::TimeDelta::FromMilliseconds(kPendingDumpTimeoutMilliseconds)); } return true; } NetlinkMessage::MessageContext NetlinkManager::InferMessageContext( const NetlinkPacket& packet) { NetlinkMessage::MessageContext context; const uint32_t sequence_number = packet.GetMessageSequence(); if (!ContainsKey(message_handlers_, sequence_number) && packet.GetMessageType() != ErrorAckMessage::kMessageType) { context.is_broadcast = true; } genlmsghdr genl_header; if (packet.GetMessageType() == Nl80211Message::GetMessageType() && packet.GetGenlMsgHdr(&genl_header)) { context.nl80211_cmd = genl_header.cmd; } return context; } void NetlinkManager::OnPendingDumpTimeout() { VLOG(3) << "Timed out waiting for replies to NL dump message " << PendingDumpSequenceNumber(); CallErrorHandler(PendingDumpSequenceNumber(), kTimeoutWaitingForResponse, nullptr); OnPendingDumpComplete(); } void NetlinkManager::OnPendingDumpComplete() { VLOG(3) << __func__; dump_pending_ = false; pending_dump_timeout_callback_.Cancel(); resend_dump_message_callback_.Cancel(); pending_messages_.pop(); if (!pending_messages_.empty()) { VLOG(3) << "Sending next pending message"; NetlinkPendingMessage to_send = pending_messages_.front(); RegisterHandlersAndSendMessage(to_send); } } bool NetlinkManager::IsDumpPending() { return dump_pending_ && !pending_messages_.empty(); } uint32_t NetlinkManager::PendingDumpSequenceNumber() { if (!IsDumpPending()) { LOG(ERROR) << __func__ << ": no pending dump"; return 0; } return pending_messages_.front().sequence_number; } bool NetlinkManager::RemoveMessageHandler(const NetlinkMessage& message) { if (!ContainsKey(message_handlers_, message.sequence_number())) { return false; } message_handlers_.erase(message.sequence_number()); return true; } uint32_t NetlinkManager::GetSequenceNumber() { return sock_ ? sock_->GetSequenceNumber() : NetlinkMessage::kBroadcastSequenceNumber; } bool NetlinkManager::SubscribeToEvents(const string& family_id, const string& group_name) { if (!ContainsKey(message_types_, family_id)) { LOG(ERROR) << "Family '" << family_id << "' doesn't exist"; return false; } if (!ContainsKey(message_types_[family_id].groups, group_name)) { LOG(ERROR) << "Group '" << group_name << "' doesn't exist in family '" << family_id << "'"; return false; } uint32_t group_id = message_types_[family_id].groups[group_name]; if (!sock_) { LOG(FATAL) << "Need to call |Init| first."; } return sock_->SubscribeToEvents(group_id); } void NetlinkManager::OnRawNlMessageReceived(InputData* data) { if (!data) { LOG(ERROR) << __func__ << "() called with null header."; return; } unsigned char* buf = data->buf; unsigned char* end = buf + data->len; while (buf < end) { NetlinkPacket packet(buf, end - buf); if (!packet.IsValid()) { break; } buf += packet.GetLength(); OnNlMessageReceived(&packet); } } void NetlinkManager::OnNlMessageReceived(NetlinkPacket* packet) { if (!packet) { LOG(ERROR) << __func__ << "() called with null packet."; return; } const uint32_t sequence_number = packet->GetMessageSequence(); std::unique_ptr<NetlinkMessage> message( message_factory_.CreateMessage(packet, InferMessageContext(*packet))); if (message == nullptr) { VLOG(3) << "NL Message " << sequence_number << " <==="; VLOG(3) << __func__ << "(msg:NULL)"; return; // Skip current message, continue parsing buffer. } VLOG(5) << "NL Message " << sequence_number << " Received (" << packet->GetLength() << " bytes) <==="; message->Print(6, 7); NetlinkMessage::PrintPacket(8, *packet); bool is_error_ack_message = false; uint32_t error_code = 0; if (message->message_type() == ErrorAckMessage::GetMessageType()) { is_error_ack_message = true; const ErrorAckMessage* error_ack_message = static_cast<const ErrorAckMessage*>(message.get()); error_code = error_ack_message->error(); } // Note: assumes we only receive one reply to a dump request: an error // message, an ACK, or a single multi-part reply. If we receive two replies, // then we will stop waiting for replies after the first reply is processed // here. This assumption should hold unless the NLM_F_ACK or NLM_F_ECHO // flags are explicitly added to the dump request. if (IsDumpPending() && (message->sequence_number() == PendingDumpSequenceNumber()) && !((message->flags() & NLM_F_MULTI) && (message->message_type() != NLMSG_DONE))) { // Dump currently in progress, this message's sequence number matches that // of the pending dump request, and we are not in the middle of receiving a // multi-part reply. if (is_error_ack_message && (error_code == static_cast<uint32_t>(-EBUSY))) { VLOG(3) << "EBUSY reply received for NL dump message " << PendingDumpSequenceNumber(); if (pending_messages_.front().retries_left) { pending_messages_.front().last_received_error = error_code; pending_dump_timeout_callback_.Cancel(); ResendPendingDumpMessageAfterDelay(); // Since we will resend the message, do not invoke error handler. return; } else { VLOG(3) << "No more resend attempts left for NL dump message " << PendingDumpSequenceNumber() << " -- stop waiting " "for replies"; OnPendingDumpComplete(); } } else { VLOG(3) << "Reply received for NL dump message " << PendingDumpSequenceNumber() << " -- stop waiting for replies"; OnPendingDumpComplete(); } } if (is_error_ack_message) { VLOG(3) << "Error/ACK response to message " << sequence_number; if (error_code) { CallErrorHandler(sequence_number, kErrorFromKernel, message.get()); } else { if (ContainsKey(message_handlers_, sequence_number)) { VLOG(6) << "Found message-specific ACK handler"; if (message_handlers_[sequence_number]->HandleAck()) { VLOG(6) << "ACK handler invoked -- removing callback"; message_handlers_.erase(sequence_number); } else { VLOG(6) << "ACK handler invoked -- not removing callback"; } } } return; } if (ContainsKey(message_handlers_, sequence_number)) { VLOG(6) << "Found message-specific handler"; if ((message->flags() & NLM_F_MULTI) && (message->message_type() == NLMSG_DONE)) { message_handlers_[sequence_number]->HandleError(kDone, message.get()); } else if (!message_handlers_[sequence_number]->HandleMessage(*message)) { LOG(ERROR) << "Couldn't call message handler for " << sequence_number; // Call the error handler but, since we don't have an |ErrorAckMessage|, // we'll have to pass a nullptr. message_handlers_[sequence_number]->HandleError(kUnexpectedResponseType, nullptr); } if ((message->flags() & NLM_F_MULTI) && (message->message_type() != NLMSG_DONE)) { VLOG(6) << "Multi-part message -- not removing callback"; } else { VLOG(6) << "Removing callbacks"; message_handlers_.erase(sequence_number); } return; } for (const auto& handler : broadcast_handlers_) { VLOG(6) << "Calling broadcast handler"; if (!handler.is_null()) { handler.Run(*message); } } } void NetlinkManager::ResendPendingDumpMessage() { if (!IsDumpPending()) { VLOG(3) << "No pending dump, so do not resend dump message"; return; } --pending_messages_.front().retries_left; if (SendMessageInternal(pending_messages_.front())) { VLOG(3) << "NL message " << PendingDumpSequenceNumber() << " sent again successfully"; return; } VLOG(3) << "Failed to resend NL message " << PendingDumpSequenceNumber(); if (pending_messages_.front().retries_left) { ResendPendingDumpMessageAfterDelay(); } else { VLOG(3) << "No more resend attempts left for NL dump message " << PendingDumpSequenceNumber() << " -- stop waiting " "for replies"; ErrorAckMessage err_message(pending_messages_.front().last_received_error); CallErrorHandler(PendingDumpSequenceNumber(), kErrorFromKernel, &err_message); OnPendingDumpComplete(); } } void NetlinkManager::CallErrorHandler(uint32_t sequence_number, AuxilliaryMessageType type, const NetlinkMessage* netlink_message) { if (ContainsKey(message_handlers_, sequence_number)) { VLOG(6) << "Found message-specific error handler"; message_handlers_[sequence_number]->HandleError(type, netlink_message); message_handlers_.erase(sequence_number); } } void NetlinkManager::OnReadError(const string& error_msg) { // TODO(wdg): When netlink_manager is used for scan, et al., this should // either be LOG(FATAL) or the code should properly deal with errors, // e.g., dropped messages due to the socket buffer being full. LOG(ERROR) << "NetlinkManager's netlink Socket read returns error: " << error_msg; } void NetlinkManager::ResendPendingDumpMessageAfterDelay() { VLOG(3) << "Resending NL dump message " << PendingDumpSequenceNumber() << " after " << kNlMessageRetryDelayMilliseconds << " ms"; resend_dump_message_callback_.Reset( Bind(&NetlinkManager::ResendPendingDumpMessage, weak_ptr_factory_.GetWeakPtr())); MessageLoop::current()->PostDelayedTask( FROM_HERE, resend_dump_message_callback_.callback(), base::TimeDelta::FromMilliseconds(kNlMessageRetryDelayMilliseconds)); } } // namespace shill.