// // 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. // // This software provides an abstracted interface to the netlink socket // interface. In its current implementation it is used, primarily, to // communicate with the cfg80211 kernel module and mac80211 drivers: // // [shill]--[nl80211 library] // | // (netlink socket) // | // [cfg80211 kernel module] // | // [mac80211 drivers] // // In order to send a message and handle it's response, do the following: // - Create a handler (it'll want to verify that it's the kind of message you // want, cast it to the appropriate type, and get attributes from the cast // message): // // #include "nl80211_message.h" // class SomeClass { // static void MyMessageHandler(const NetlinkMessage& raw) { // if (raw.message_type() != ControlNetlinkMessage::kMessageType) // return; // const ControlNetlinkMessage* message = // reinterpret_cast(&raw); // if (message.command() != NewFamilyMessage::kCommand) // return; // uint16_t my_attribute; // message->const_attributes()->GetU16AttributeValue( // CTRL_ATTR_FAMILY_ID, &my_attribute); // } // MyMessageHandler. // } // class SomeClass. // // - Instantiate a message: // // #include "nl80211_message.h" // GetFamilyMessage msg; // // - And set attributes: // // msg.attributes()->SetStringAttributeValue(CTRL_ATTR_FAMILY_NAME, "foo"); // // - Then send the message, passing-in a closure to the handler you created: // // NetlinkManager* netlink_manager = NetlinkManager::GetInstance(); // netlink_manager->SendMessage(&msg, Bind(&SomeClass::MyMessageHandler)); // // NetlinkManager will then save your handler and send your message. When a // response to your message arrives, it'll call your handler. // #ifndef SHILL_NET_NETLINK_MANAGER_H_ #define SHILL_NET_NETLINK_MANAGER_H_ #include #include #include #include #include #include #include #include #include #include #include // for FRIEND_TEST #include "shill/net/generic_netlink_message.h" #include "shill/net/io_handler_factory_container.h" #include "shill/net/netlink_message.h" #include "shill/net/netlink_socket.h" #include "shill/net/shill_export.h" #include "shill/net/shill_time.h" namespace shill { class ControlNetlinkMessage; struct InputData; class NetlinkPacket; class Nl80211Message; // NetlinkManager is a singleton that coordinates sending netlink messages to, // and receiving netlink messages from, the kernel. The first use of this is // to communicate between user-space and the cfg80211 module that manages wifi // drivers. Bring NetlinkManager up as follows: // NetlinkManager* netlink_manager_ = NetlinkManager::GetInstance(); // netlink_manager_->Init(); // Initialize the socket. // // Get message types for all dynamic message types. // Nl80211Message::SetMessageType( // netlink_manager_->GetFamily(Nl80211Message::kMessageTypeString, // Bind(&Nl80211Message::CreateMessage))); // netlink_manager_->Start(); class SHILL_EXPORT NetlinkManager { public: enum AuxilliaryMessageType { kDone, kErrorFromKernel, kTimeoutWaitingForResponse, kUnexpectedResponseType }; typedef base::Callback NetlinkMessageHandler; typedef base::Callback ControlNetlinkMessageHandler; typedef base::Callback Nl80211MessageHandler; // NetlinkAuxilliaryMessageHandler handles netlink error messages, things // like the DoneMessage at the end of a multi-part message, and any errors // discovered by |NetlinkManager| (which are passed as NULL pointers because // there is no way to reserve a part of the ErrorAckMessage space for // non-netlink errors). typedef base::Callback NetlinkAuxilliaryMessageHandler; // NetlinkAckHandler handles netlink Ack messages, which are a special type // of netlink error message carrying an error code of 0. Since Ack messages // contain no useful data (other than the error code of 0 to differentiate // it from an actual error message), the handler is not passed a message. // as an argument. The boolean value filled in by the handler (via the // pointer) indicates whether or not the callbacks registered for the message // (identified by sequence number) that this handler was invoked for should be // removed after this callback is executed. This allows a sender of an NL80211 // message to handle both an Ack and another response message, rather than // handle only the first response received. typedef base::Callback NetlinkAckHandler; // ResponseHandlers provide a polymorphic context for the base::Callback // message handlers so that handlers for different types of messages can be // kept in the same container (namely, |message_handlers_|). class NetlinkResponseHandler : public base::RefCounted { public: explicit NetlinkResponseHandler( const NetlinkAckHandler& ack_handler, const NetlinkAuxilliaryMessageHandler& error_handler); virtual ~NetlinkResponseHandler(); // Calls wrapper-type-specific callback for |netlink_message|. Returns // false if |netlink_message| is not the correct type. Calls callback // (which is declared in the private area of derived classes) with // properly cast version of |netlink_message|. virtual bool HandleMessage(const NetlinkMessage& netlink_message) const = 0; void HandleError(AuxilliaryMessageType type, const NetlinkMessage* netlink_message) const; virtual bool HandleAck() const; void set_delete_after(const timeval& time) { delete_after_ = time; } const struct timeval& delete_after() const { return delete_after_; } protected: NetlinkResponseHandler(); NetlinkAckHandler ack_handler_; private: NetlinkAuxilliaryMessageHandler error_handler_; struct timeval delete_after_; DISALLOW_COPY_AND_ASSIGN(NetlinkResponseHandler); }; // Encapsulates all the different things we know about a specific message // type like its name, and its id. struct MessageType { MessageType(); uint16_t family_id; // Multicast groups supported by the family. The string and mapping to // a group id are extracted from the CTRL_CMD_NEWFAMILY message. std::map groups; }; // Various kinds of events to which we can subscribe (and receive) from // cfg80211. static const char kEventTypeConfig[]; static const char kEventTypeScan[]; static const char kEventTypeRegulatory[]; static const char kEventTypeMlme[]; // NetlinkManager is a singleton and this is the way to access it. static NetlinkManager* GetInstance(); virtual ~NetlinkManager(); // Performs non-trivial object initialization of the NetlinkManager singleton. virtual bool Init(); // Passes the job of waiting for, and the subsequent reading from, the // netlink socket to the current message loop. virtual void Start(); // The following methods deal with the network family table. This table // associates netlink family names with family_ids (also called message // types). Note that some families have static ids assigned to them but // others require the kernel to resolve a string describing the family into // a dynamically-determined id. // Returns the family_id (message type) associated with |family_name|, // calling the kernel if needed. Returns // |NetlinkMessage::kIllegalMessageType| if the message type could not be // determined. May block so |GetFamily| should be called before entering the // event loop. virtual uint16_t GetFamily(const std::string& family_name, const NetlinkMessageFactory::FactoryMethod& message_factory); // Install a NetlinkManager NetlinkMessageHandler. The handler is a // user-supplied object to be called by the system for user-bound messages // that do not have a corresponding messaage-specific callback. // |AddBroadcastHandler| should be called before |SubscribeToEvents| since // the result of this call are used for that call. virtual bool AddBroadcastHandler( const NetlinkMessageHandler& message_handler); // Uninstall a NetlinkMessage Handler. virtual bool RemoveBroadcastHandler( const NetlinkMessageHandler& message_handler); // Determines whether a handler is in the list of broadcast handlers. bool FindBroadcastHandler(const NetlinkMessageHandler& message_handler) const; // Uninstall all broadcast netlink message handlers. void ClearBroadcastHandlers(); // Sends a netlink message to the kernel using the NetlinkManager socket after // installing a handler to deal with the kernel's response to the message. // TODO(wdg): Eventually, this should also include a timeout and a callback // to call in case of timeout. virtual bool SendControlMessage( ControlNetlinkMessage* message, const ControlNetlinkMessageHandler& message_handler, const NetlinkAckHandler& ack_handler, const NetlinkAuxilliaryMessageHandler& error_handler); virtual bool SendNl80211Message( Nl80211Message* message, const Nl80211MessageHandler& message_handler, const NetlinkAckHandler& ack_handler, const NetlinkAuxilliaryMessageHandler& error_handler); // Generic erroneous message handler everyone can use. static void OnNetlinkMessageError(AuxilliaryMessageType type, const NetlinkMessage* raw_message); // Generic Ack handler that does nothing. Other callbacks registered for the // message are not deleted after this function is executed. static void OnAckDoNothing(bool* remove_callbacks) { *remove_callbacks = false; } // Uninstall the handler for a specific netlink message. bool RemoveMessageHandler(const NetlinkMessage& message); // Sign-up to receive and log multicast events of a specific type (once wifi // is up). virtual bool SubscribeToEvents(const std::string& family, const std::string& group); // Gets the next sequence number for a NetlinkMessage to be sent over // NetlinkManager's netlink socket. uint32_t GetSequenceNumber(); protected: friend struct base::DefaultLazyInstanceTraits; NetlinkManager(); private: friend class NetlinkManagerTest; friend class NetlinkMessageTest; friend class ShillDaemonTest; friend class ChromeosDaemonTest; FRIEND_TEST(NetlinkManagerTest, AddLinkTest); FRIEND_TEST(NetlinkManagerTest, BroadcastHandler); FRIEND_TEST(NetlinkManagerTest, GetFamilyOneInterstitialMessage); FRIEND_TEST(NetlinkManagerTest, GetFamilyTimeout); FRIEND_TEST(NetlinkManagerTest, MessageHandler); FRIEND_TEST(NetlinkManagerTest, AckHandler); FRIEND_TEST(NetlinkManagerTest, ErrorHandler); FRIEND_TEST(NetlinkManagerTest, MultipartMessageHandler); FRIEND_TEST(NetlinkManagerTest, OnInvalidRawNlMessageReceived); FRIEND_TEST(NetlinkManagerTest, TimeoutResponseHandlers); FRIEND_TEST(NetlinkManagerTest, PendingDump); FRIEND_TEST(NetlinkManagerTest, PendingDump_Timeout); FRIEND_TEST(NetlinkManagerTest, PendingDump_Retry); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_ASSOCIATE); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_AUTHENTICATE); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_CONNECT); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DEAUTHENTICATE); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DISASSOCIATE); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DISCONNECT); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NEW_SCAN_RESULTS); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NEW_STATION); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NOTIFY_CQM); FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_TRIGGER_SCAN); typedef scoped_refptr NetlinkResponseHandlerRefPtr; // Container for information we need to send a netlink message out on a // netlink socket. struct NetlinkPendingMessage { NetlinkPendingMessage(uint32_t sequence_number_arg, bool is_dump_request_arg, ByteString message_string_arg, NetlinkResponseHandlerRefPtr handler_arg) : retries_left(kMaxNlMessageRetries), sequence_number(sequence_number_arg), is_dump_request(is_dump_request_arg), message_string(message_string_arg), handler(handler_arg) {} int retries_left; uint32_t sequence_number; bool is_dump_request; ByteString message_string; NetlinkResponseHandlerRefPtr handler; uint32_t last_received_error; }; // These need to be member variables, even though they're only used once in // the code, since they're needed for unittests. static const long kMaximumNewFamilyWaitSeconds; // NOLINT static const long kMaximumNewFamilyWaitMicroSeconds; // NOLINT static const long kResponseTimeoutSeconds; // NOLINT static const long kResponseTimeoutMicroSeconds; // NOLINT static const long kPendingDumpTimeoutMilliseconds; // NOLINT static const long kNlMessageRetryDelayMilliseconds; // NOLINT static const int kMaxNlMessageRetries; // NOLINT // Returns the file descriptor of socket used to read wifi data. int file_descriptor() const; // MessageLoop calls this when data is available on our socket. This // method passes each, individual, message in the input to // |OnNlMessageReceived|. Each part of a multipart message gets handled, // individually, by this method. void OnRawNlMessageReceived(InputData* data); // This method processes a message from |OnRawNlMessageReceived| by passing // the message to either the NetlinkManager callback that matches the sequence // number of the message or, if there isn't one, to all of the default // NetlinkManager callbacks in |broadcast_handlers_|. void OnNlMessageReceived(NetlinkPacket* packet); // Sends the pending dump message, and decrement the message's retry count if // it was resent successfully. void ResendPendingDumpMessage(); // If a NetlinkResponseHandler registered for the message identified by // |sequence_number| exists, calls the error handler with the arguments |type| // and |netlink_message|, then erases the NetlinkResponseHandler from // |message_handlers_|. void CallErrorHandler(uint32_t sequence_number, AuxilliaryMessageType type, const NetlinkMessage* netlink_message); // Called by InputHandler on exceptional events. void OnReadError(const std::string& error_msg); // Utility function that posts a task to the message loop to call // NetlinkManager::ResendPendingDumpMessage kNlMessageRetryDelayMilliseconds // from now. void ResendPendingDumpMessageAfterDelay(); // Just for tests, this method turns off WiFi and clears the subscribed // events list. If |full| is true, also clears state set by Init. void Reset(bool full); // Handles a CTRL_CMD_NEWFAMILY message from the kernel. void OnNewFamilyMessage(const ControlNetlinkMessage& message); // Sends a netlink message if |pending_dump_| is false. Otherwise, post // a message to |pending_messages_| to be sent later. bool SendOrPostMessage( NetlinkMessage* message, NetlinkResponseHandler* message_wrapper); // Passes ownership. // Install a handler to deal with kernel's response to the message contained // in |pending_message|, then sends the message by calling // NetlinkManager::SendMessageInternal. bool RegisterHandlersAndSendMessage( const NetlinkPendingMessage& pending_message); // Sends the netlink message whose bytes are contained in |pending_message| to // the kernel using the NetlinkManager socket. If |pending_message| is a dump // request and the message is sent successfully, a timeout timer is started to // limit the amount of time we wait for responses to that message. Adds a // serial number to |message| before it is sent. bool SendMessageInternal(const NetlinkPendingMessage& pending_message); // Given a netlink packet |packet|, infers the context of this netlink // message (for message parsing purposes) and returns a MessageContext // describing this context. NetlinkMessage::MessageContext InferMessageContext( const NetlinkPacket& packet); // Called when we time out waiting for a response to a netlink dump message. // Invokes the error handler with kTimeoutWaitingForResponse, deletes the // error handler, then calls NetlinkManager::OnPendingDumpComplete. void OnPendingDumpTimeout(); // Cancels |pending_dump_timeout_callback_|, deletes the currently pending // dump request message from the front of |pending_messages_| since we have // finished waiting for replies, then sends the next message in // |pending_messages_| (if any). void OnPendingDumpComplete(); // Returns true iff there we are waiting for replies to a netlink dump // message, false otherwise. bool IsDumpPending(); // Returns the sequence number of the pending netlink dump request message iff // there is a pending dump. Otherwise, returns 0. uint32_t PendingDumpSequenceNumber(); // NetlinkManager Handlers, OnRawNlMessageReceived invokes each of these // User-supplied callback object when _it_ gets called to read netlink data. std::list broadcast_handlers_; // Message-specific callbacks, mapped by message ID. std::map message_handlers_; // Netlink messages due to be sent to the kernel. If a dump is pending, // the first element in this queue will contain the netlink dump request // message that we are waiting on replies for. std::queue pending_messages_; base::WeakPtrFactory weak_ptr_factory_; base::CancelableClosure pending_dump_timeout_callback_; base::CancelableClosure resend_dump_message_callback_; base::Callback dispatcher_callback_; std::unique_ptr dispatcher_handler_; std::unique_ptr sock_; std::map message_types_; NetlinkMessageFactory message_factory_; Time* time_; IOHandlerFactory* io_handler_factory_; bool dump_pending_; DISALLOW_COPY_AND_ASSIGN(NetlinkManager); }; } // namespace shill #endif // SHILL_NET_NETLINK_MANAGER_H_