| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This library provides an abstracted interface to the cfg80211 kernel module |
| // and mac80211 drivers. These are accessed via a netlink socket using the |
| // following software stack: |
| // |
| // [shill] |
| // | |
| // [nl80211 library] |
| // | |
| // [libnl_genl/libnl libraries] |
| // | |
| // (netlink socket) |
| // | |
| // [cfg80211 kernel module] |
| // | |
| // [mac80211 drivers] |
| // |
| // Messages go from user-space to kernel-space (i.e., Kernel-Bound) or in the |
| // other direction (i.e., User-Bound). |
| // |
| // For the love of Pete, there are a lot of different types of callbacks, |
| // here. I'll try to differentiate: |
| // |
| // Config80211 Callback - |
| // This is a base::Callback object installed by the user and called by |
| // Config80211 for each message it receives. More specifically, when the |
| // user calls Config80211::SubscribeToEvents, Config80211 installs |
| // OnNlMessageReceived as a netlink callback function (described below). |
| // OnNlMessageReceived, in turn, parses the message from cfg80211 and calls |
| // Config80211::Callback with the resultant UserBoundNlMessage. |
| // |
| // Netlink Callback - |
| // Netlink callbacks are mechanisms installed by the user (well, by |
| // Config80211 -- none of these are intended for use by users of |
| // Config80211) for the libnl layer to communicate back to the user. Some |
| // callbacks are installed for global use (i.e., the default callback used |
| // for all messages) or as an override for a specific message. Netlink |
| // callbacks come in three levels. |
| // |
| // The lowest level (nl_recvmsg_msg_cb_t) is a function installed by |
| // Config80211. These are called by libnl when messages are received from |
| // the kernel. |
| // |
| // The medium level (nl_cb) is also used by Config80211. This, the 'netlink |
| // callback structure', encapsualtes a number of netlink callback functions |
| // (nl_recvmsg_msg_cb_t, one each for different types of messages). |
| // |
| // The highest level is the NetlinkSocket::Callback object. |
| // |
| // Dispatcher Callback - |
| // This base::Callback is a private method of Config80211 created and |
| // installed behind the scenes. This is not the callback you're looking |
| // for; move along. This is called by shill's EventDispatcher when there's |
| // data waiting for user space code on the netlink socket. This callback |
| // then calls NetlinkSocket::GetMessages which calls nl_recvmsgs_default |
| // which, in turn, calls the installed netlink callback function. |
| |
| #ifndef SHILL_CONFIG80211_H_ |
| #define SHILL_CONFIG80211_H_ |
| |
| #include <iomanip> |
| #include <map> |
| #include <set> |
| #include <string> |
| |
| #include <base/basictypes.h> |
| #include <base/bind.h> |
| #include <base/lazy_instance.h> |
| |
| #include "shill/event_dispatcher.h" |
| #include "shill/io_handler.h" |
| #include "shill/nl80211_socket.h" |
| |
| namespace shill { |
| |
| class KernelBoundNlMessage; |
| class UserBoundNlMessage; |
| |
| // Provides a transport-independent ability to receive status from the wifi |
| // configuration. In its current implementation, it uses the netlink socket |
| // interface to interface with the wifi system. |
| // |
| // Config80211 is a singleton and, as such, coordinates access to libnl. |
| class Config80211 { |
| public: |
| typedef base::Callback<void(const UserBoundNlMessage &)> Callback; |
| |
| // The different kinds of events to which we can subscribe (and receive) |
| // from cfg80211. |
| enum EventType { |
| kEventTypeConfig, |
| kEventTypeScan, |
| kEventTypeRegulatory, |
| kEventTypeMlme, |
| kEventTypeCount |
| }; |
| |
| // This represents whether the cfg80211/mac80211 are installed in the kernel. |
| enum WifiState { |
| kWifiUp, |
| kWifiDown |
| }; |
| |
| virtual ~Config80211(); |
| |
| // This is a singleton -- use Config80211::GetInstance()->Foo() |
| static Config80211 *GetInstance(); |
| |
| // Performs non-trivial object initialization of the Config80211 singleton. |
| bool Init(EventDispatcher *dispatcher); |
| |
| // Returns the file descriptor of socket used to read wifi data. |
| int GetFd() const { return (sock_ ? sock_->GetFd() : -1); } |
| |
| // Install default Config80211 Callback. The callback is a user-supplied |
| // object to be called by the system for user-bound messages that do not |
| // have a corresponding messaage-specific callback. |SetDefaultCallback| |
| // should be called before |SubscribeToEvents| since the result of this call |
| // are used for that call. |
| void SetDefaultCallback(const Callback &callback) { |
| default_callback_ = callback; } |
| |
| // Uninstall default Config80211 Callback. |
| void UnsetDefaultCallback() { default_callback_.Reset(); } |
| |
| // TODO(wdg): Add 'SendMessage(KernelBoundNlMessage *message, |
| // Config80211::Callback *callback); |
| // Config80211 needs to handle out-of-order responses using a |
| // map <sequence_number, callback> to match callback with message. |
| |
| // Return a string corresponding to the passed-in EventType. |
| static bool GetEventTypeString(EventType type, std::string *value); |
| |
| // Sign-up to receive and log multicast events of a specific type (once wifi |
| // is up). |
| bool SubscribeToEvents(EventType type); |
| |
| // Indicate that the mac80211 driver is up and, ostensibly, accepting event |
| // subscription requests or down. |
| void SetWifiState(WifiState new_state); |
| |
| protected: |
| friend struct base::DefaultLazyInstanceTraits<Config80211>; |
| |
| explicit Config80211(); |
| |
| private: |
| friend class Config80211Test; |
| typedef std::map<EventType, std::string> EventTypeStrings; |
| typedef std::set<EventType> SubscribedEvents; |
| |
| // Sign-up to receive and log multicast events of a specific type (assumes |
| // wifi is up). |
| bool ActuallySubscribeToEvents(EventType type); |
| |
| // EventDispatcher calls this when data is available on our socket. This |
| // callback reads data from the driver, parses that data, and logs it. |
| void HandleIncomingEvents(int fd); |
| |
| // This is a Netlink Callback. libnl-80211 calls this method when it |
| // receives data from cfg80211. This method parses those messages and logs |
| // them. |
| static int OnNlMessageReceived(struct nl_msg *msg, void *arg); |
| |
| // Just for tests, this method turns off WiFi and clears the subscribed |
| // events list. |
| void Reset(); |
| |
| // Config80211 Callback, OnNlMessageReceived invokes this User-supplied |
| // callback object when _it_ gets called to read libnl data. |
| Callback default_callback_; |
| |
| // TODO(wdg): implement the following. |
| // std::map<uint32_t, Callback> message_callback_; |
| |
| static EventTypeStrings *event_types_; |
| |
| WifiState wifi_state_; |
| |
| SubscribedEvents subscribed_events_; |
| |
| // Hooks needed to be called by shill's EventDispatcher. |
| EventDispatcher *dispatcher_; |
| base::WeakPtrFactory<Config80211> weak_ptr_factory_; |
| base::Callback<void(int)> dispatcher_callback_; |
| scoped_ptr<IOHandler> dispatcher_handler_; |
| |
| Nl80211Socket *sock_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Config80211); |
| }; |
| |
| } // namespace shill |
| |
| #endif // SHILL_CONFIG80211_H_ |