blob: 7d4d5813a28a09df0ce453a5a75fe687a214cf1f [file] [log] [blame]
// 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]
#ifndef SHILL_CONFIG80211_H_
#define SHILL_CONFIG80211_H_
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include <iomanip>
#include <list>
#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 Error;
struct InputData;
class NetlinkMessage;
// 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 NetlinkMessage &)> NetlinkMessageHandler;
// 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 a Config80211 NetlinkMessageHandler. 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.
// |AddBroadcastHandler| should be called before |SubscribeToEvents| since
// the result of this call are used for that call.
bool AddBroadcastHandler(const NetlinkMessageHandler &messge_handler);
// Uninstall a Config80211 Handler.
bool RemoveBroadcastHandler(const NetlinkMessageHandler &message_handler);
// Determines whether a callback is in the list of broadcast callbacks.
bool FindBroadcastHandler(const NetlinkMessageHandler &message_handler) const;
// Uninstall all broadcast netlink message handlers.
void ClearBroadcastHandlers();
// Sends a kernel-bound message using the Config80211 socket after installing
// a callback to handle it.
// TODO(wdg): Eventually, this should also include a timeout and a callback
// to call in case of timeout.
bool SendMessage(NetlinkMessage *message, const NetlinkMessageHandler
&message_handler);
// Uninstall a Config80211 Handler for a specific message.
bool RemoveMessageHandler(const NetlinkMessage &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);
// Gets the next sequence number for a NetlinkMessage to be sent over
// Config80211's netlink socket.
uint32_t GetSequenceNumber();
protected:
friend struct base::DefaultLazyInstanceTraits<Config80211>;
explicit Config80211();
private:
friend class Config80211Test;
friend class ShillDaemonTest;
FRIEND_TEST(Config80211Test, BroadcastHandlerTest);
FRIEND_TEST(Config80211Test, MessageHandlerTest);
typedef std::map<EventType, std::string> EventTypeStrings;
typedef std::set<EventType> SubscribedEvents;
typedef std::map<uint32_t, NetlinkMessageHandler> MessageHandlers;
// 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
// method passes each, individual, message in the input to
// |OnNlMessageReceived|.
void OnRawNlMessageReceived(InputData *data);
// This method processes a message from |OnRawNlMessageReceived| by passing
// the message to either the Config80211 callback that matches the sequence
// number of the message or, if there isn't one, to all of the default
// Config80211 callbacks in |broadcast_handlers_|.
void OnNlMessageReceived(nlmsghdr *msg);
// Called by InputHandler on exceptional events.
void OnReadError(const Error &error);
// 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);
// Config80211 Handlers, OnRawNlMessageReceived invokes each of these
// User-supplied callback object when _it_ gets called to read libnl data.
std::list<NetlinkMessageHandler> broadcast_handlers_;
// Message-specific callbacks, mapped by message ID.
MessageHandlers message_handlers_;
static EventTypeStrings *event_types_;
WifiState wifi_state_;
// The subscribed multicast groups exist on a per-socket basis.
SubscribedEvents subscribed_events_;
// Hooks needed to be called by shill's EventDispatcher.
EventDispatcher *dispatcher_;
base::WeakPtrFactory<Config80211> weak_ptr_factory_;
base::Callback<void(InputData *)> dispatcher_callback_;
scoped_ptr<IOHandler> dispatcher_handler_;
Nl80211Socket *sock_;
DISALLOW_COPY_AND_ASSIGN(Config80211);
};
} // namespace shill
#endif // SHILL_CONFIG80211_H_