blob: 1d714e244499c70d3dc4b968b561dfdcb9950e84 [file] [log] [blame]
Wade Guthrie0d438532012-05-18 14:18:50 -07001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Wade Guthriebee87c22013-03-06 11:00:46 -08005// This software provides an abstracted interface to the netlink socket
6// interface. In its current implementation it is used, primarily, to
7// communicate with the cfg80211 kernel module and mac80211 drivers:
Wade Guthrie0d438532012-05-18 14:18:50 -07008//
repo syncbcaa6942013-01-02 15:38:21 -08009// [shill]--[nl80211 library, libnl_genl/libnl libraries]
10// |
11// (netlink socket)
12// |
Wade Guthrie0d438532012-05-18 14:18:50 -070013// [cfg80211 kernel module]
repo syncbcaa6942013-01-02 15:38:21 -080014// |
15// [mac80211 drivers]
Wade Guthriebee87c22013-03-06 11:00:46 -080016//
17// In order to send a message and handle it's response, do the following:
18// - Create a handler (it'll want to verify that it's the kind of message you
19// want, cast it to the appropriate type, and get attributes from the cast
20// message):
21//
22// #include "nl80211_message.h"
23// class SomeClass {
24// static void MyMessageHandler(const NetlinkMessage &raw) {
25// if (raw.message_type() != ControlNetlinkMessage::kMessageType)
26// return;
27// const ControlNetlinkMessage *message =
28// reinterpret_cast<const ControlNetlinkMessage *>(&raw);
29// if (message.command() != NewFamilyMessage::kCommand)
30// return;
31// uint16_t my_attribute;
32// message->const_attributes()->GetU16AttributeValue(
33// CTRL_ATTR_FAMILY_ID, &my_attribute);
34// } // MyMessageHandler.
35// } // class SomeClass.
36//
37// - Instantiate a message:
38//
39// #include "nl80211_message.h"
40// GetFamilyMessage msg;
41//
Wade Guthrie2623f1a2013-05-14 15:14:54 -070042// - And set attributes:
Wade Guthriebee87c22013-03-06 11:00:46 -080043//
Wade Guthrie2623f1a2013-05-14 15:14:54 -070044// msg.attributes()->SetStringAttributeValue(CTRL_ATTR_FAMILY_NAME, "foo");
Wade Guthriebee87c22013-03-06 11:00:46 -080045//
46// - Then send the message, passing-in a closure to the handler you created:
47//
Wade Guthriebb9fca22013-04-10 17:21:42 -070048// NetlinkManager *netlink_manager = NetlinkManager::GetInstance();
49// netlink_manager->SendMessage(&msg, Bind(&SomeClass::MyMessageHandler));
Wade Guthriebee87c22013-03-06 11:00:46 -080050//
Wade Guthriebb9fca22013-04-10 17:21:42 -070051// NetlinkManager will then save your handler and send your message. When a
Wade Guthriebee87c22013-03-06 11:00:46 -080052// response to your message arrives, it'll call your handler.
53//
Wade Guthrie0d438532012-05-18 14:18:50 -070054
Wade Guthriebb9fca22013-04-10 17:21:42 -070055#ifndef SHILL_NETLINK_MANAGER_H_
56#define SHILL_NETLINK_MANAGER_H_
Wade Guthrie0d438532012-05-18 14:18:50 -070057
Wade Guthrieb1ec8602012-10-18 17:26:14 -070058#include <list>
Wade Guthrie0d438532012-05-18 14:18:50 -070059#include <map>
Wade Guthried6153612012-08-23 11:36:14 -070060#include <set>
Wade Guthrie0d438532012-05-18 14:18:50 -070061#include <string>
62
63#include <base/basictypes.h>
64#include <base/bind.h>
65#include <base/lazy_instance.h>
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070066#include <base/memory/scoped_ptr.h>
67#include <gtest/gtest_prod.h> // for FRIEND_TEST
Wade Guthrie0d438532012-05-18 14:18:50 -070068
Wade Guthrie7347bf22013-04-30 11:21:51 -070069#include "shill/generic_netlink_message.h"
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070070#include "shill/io_handler.h"
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -070071#include "shill/netlink_message.h"
Wade Guthriefa2100e2013-05-15 10:11:22 -070072#include "shill/shill_time.h"
Wade Guthrie12f113a2013-03-12 17:15:46 -070073
Wade Guthrie89e6cb32013-03-07 08:03:45 -080074struct nlmsghdr;
Wade Guthrie0d438532012-05-18 14:18:50 -070075
76namespace shill {
77
Wade Guthrie7347bf22013-04-30 11:21:51 -070078class ControlNetlinkMessage;
repo syncbcaa6942013-01-02 15:38:21 -080079class Error;
Wade Guthrie89e6cb32013-03-07 08:03:45 -080080class EventDispatcher;
Liam McLoughlinf4baef22012-08-01 19:08:25 -070081struct InputData;
Wade Guthrie89e6cb32013-03-07 08:03:45 -080082class NetlinkSocket;
Wade Guthrie7347bf22013-04-30 11:21:51 -070083class Nl80211Message;
Wade Guthrie0d438532012-05-18 14:18:50 -070084
Wade Guthriebb9fca22013-04-10 17:21:42 -070085// NetlinkManager is a singleton that coordinates sending netlink messages to,
Wade Guthriebee87c22013-03-06 11:00:46 -080086// and receiving netlink messages from, the kernel. The first use of this is
87// to communicate between user-space and the cfg80211 module that manages wifi
Wade Guthriebb9fca22013-04-10 17:21:42 -070088// drivers. Bring NetlinkManager up as follows:
89// NetlinkManager *netlink_manager_ = NetlinkManager::GetInstance();
Wade Guthriebee87c22013-03-06 11:00:46 -080090// EventDispatcher dispatcher_;
Wade Guthriebb9fca22013-04-10 17:21:42 -070091// netlink_manager_->Init(); // Initialize the socket.
Wade Guthriebee87c22013-03-06 11:00:46 -080092// // Get message types for all dynamic message types.
93// Nl80211Message::SetMessageType(
Wade Guthriebb9fca22013-04-10 17:21:42 -070094// netlink_manager_->GetFamily(Nl80211Message::kMessageTypeString,
Wade Guthriebee87c22013-03-06 11:00:46 -080095// Bind(&Nl80211Message::CreateMessage)));
Wade Guthriebb9fca22013-04-10 17:21:42 -070096// netlink_manager_->Start(&dispatcher_);
97class NetlinkManager {
Wade Guthrie0d438532012-05-18 14:18:50 -070098 public:
Wade Guthrie84db7ce2013-06-12 11:40:49 -070099 enum AuxilliaryMessageType {
100 kErrorFromKernel,
101 kUnexpectedResponseType,
102 kTimeoutWaitingForResponse
103 };
Wade Guthrief48a1952013-03-04 17:33:47 -0800104 typedef base::Callback<void(const NetlinkMessage &)> NetlinkMessageHandler;
Wade Guthrie7347bf22013-04-30 11:21:51 -0700105 typedef base::Callback<void(const ControlNetlinkMessage &)>
106 ControlNetlinkMessageHandler;
107 typedef base::Callback<void(const Nl80211Message &)> Nl80211MessageHandler;
108 // NetlinkAuxilliaryMessageHandler handles netlink error messages, things
109 // like the DoneMessage at the end of a multi-part message, and any errors
110 // discovered by |NetlinkManager| (which are passed as NULL pointers because
111 // there is no way to reserve a part of the ErrorAckMessage space for
112 // non-netlink errors).
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700113 typedef base::Callback<void(AuxilliaryMessageType type,
114 const NetlinkMessage *)>
Wade Guthrie7347bf22013-04-30 11:21:51 -0700115 NetlinkAuxilliaryMessageHandler;
116
117 // ResponseHandlers provide a polymorphic context for the base::Callback
118 // message handlers so that handlers for different types of messages can be
119 // kept in the same container (namely, |message_handlers_|).
120 class NetlinkResponseHandler :
121 public base::RefCounted<NetlinkResponseHandler> {
122 public:
123 explicit NetlinkResponseHandler(
124 const NetlinkAuxilliaryMessageHandler &error_handler);
125 virtual ~NetlinkResponseHandler();
126 // Calls wrapper-type-specific callback for |netlink_message|. Returns
127 // false if |netlink_message| is not the correct type. Calls callback
128 // (which is declared in the private area of derived classes) with
129 // properly cast version of |netlink_message|.
130 virtual bool HandleMessage(const NetlinkMessage &netlink_message) const = 0;
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700131 void HandleError(AuxilliaryMessageType type,
132 const NetlinkMessage *netlink_message) const;
133 void set_delete_after(const timeval &time) { delete_after_ = time; }
134 const struct timeval &delete_after() const { return delete_after_; }
Wade Guthrie7347bf22013-04-30 11:21:51 -0700135
136 protected:
137 NetlinkResponseHandler();
138
139 private:
140 NetlinkAuxilliaryMessageHandler error_handler_;
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700141 struct timeval delete_after_;
Wade Guthrie7347bf22013-04-30 11:21:51 -0700142
143 DISALLOW_COPY_AND_ASSIGN(NetlinkResponseHandler);
144 };
Wade Guthrie0d438532012-05-18 14:18:50 -0700145
Wade Guthriebee87c22013-03-06 11:00:46 -0800146 // Encapsulates all the different things we know about a specific message
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -0700147 // type like its name, and its id.
Wade Guthriebee87c22013-03-06 11:00:46 -0800148 struct MessageType {
149 MessageType();
150
151 uint16_t family_id;
152
153 // Multicast groups supported by the family. The string and mapping to
154 // a group id are extracted from the CTRL_CMD_NEWFAMILY message.
155 std::map<std::string, uint32_t> groups;
Wade Guthrie0d438532012-05-18 14:18:50 -0700156 };
157
Wade Guthriebee87c22013-03-06 11:00:46 -0800158 // Various kinds of events to which we can subscribe (and receive) from
159 // cfg80211.
160 static const char kEventTypeConfig[];
161 static const char kEventTypeScan[];
162 static const char kEventTypeRegulatory[];
163 static const char kEventTypeMlme[];
164
Wade Guthriebb9fca22013-04-10 17:21:42 -0700165 // NetlinkManager is a singleton and this is the way to access it.
166 static NetlinkManager *GetInstance();
Wade Guthrie0d438532012-05-18 14:18:50 -0700167
Wade Guthriebb9fca22013-04-10 17:21:42 -0700168 // Performs non-trivial object initialization of the NetlinkManager singleton.
Wade Guthriebee87c22013-03-06 11:00:46 -0800169 bool Init();
Wade Guthrie0d438532012-05-18 14:18:50 -0700170
Wade Guthriebee87c22013-03-06 11:00:46 -0800171 // Passes the job of waiting for, and the subsequent reading from, the
172 // netlink socket to |dispatcher|.
173 void Start(EventDispatcher *dispatcher);
Wade Guthrie0d438532012-05-18 14:18:50 -0700174
Wade Guthriebee87c22013-03-06 11:00:46 -0800175 // The following methods deal with the network family table. This table
176 // associates netlink family names with family_ids (also called message
177 // types). Note that some families have static ids assigned to them but
178 // others require the kernel to resolve a string describing the family into
179 // a dynamically-determined id.
180
181 // Returns the family_id (message type) associated with |family_name|,
182 // calling the kernel if needed. Returns
183 // |NetlinkMessage::kIllegalMessageType| if the message type could not be
184 // determined. May block so |GetFamily| should be called before entering the
185 // event loop.
Wade Guthriefa2100e2013-05-15 10:11:22 -0700186 virtual uint16_t GetFamily(const std::string &family_name,
Wade Guthrie12f113a2013-03-12 17:15:46 -0700187 const NetlinkMessageFactory::FactoryMethod &message_factory);
Wade Guthriebee87c22013-03-06 11:00:46 -0800188
Wade Guthriebb9fca22013-04-10 17:21:42 -0700189 // Install a NetlinkManager NetlinkMessageHandler. The handler is a
Wade Guthrie71cb0a72013-02-27 10:27:18 -0800190 // user-supplied object to be called by the system for user-bound messages
191 // that do not have a corresponding messaage-specific callback.
192 // |AddBroadcastHandler| should be called before |SubscribeToEvents| since
193 // the result of this call are used for that call.
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700194 virtual bool AddBroadcastHandler(
195 const NetlinkMessageHandler &message_handler);
Wade Guthrie0d438532012-05-18 14:18:50 -0700196
Wade Guthriebee87c22013-03-06 11:00:46 -0800197 // Uninstall a NetlinkMessage Handler.
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700198 virtual bool RemoveBroadcastHandler(
199 const NetlinkMessageHandler &message_handler);
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700200
Wade Guthriebee87c22013-03-06 11:00:46 -0800201 // Determines whether a handler is in the list of broadcast handlers.
Wade Guthrie71cb0a72013-02-27 10:27:18 -0800202 bool FindBroadcastHandler(const NetlinkMessageHandler &message_handler) const;
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700203
Wade Guthrie71cb0a72013-02-27 10:27:18 -0800204 // Uninstall all broadcast netlink message handlers.
205 void ClearBroadcastHandlers();
Wade Guthrie0d438532012-05-18 14:18:50 -0700206
Wade Guthriebb9fca22013-04-10 17:21:42 -0700207 // Sends a netlink message to the kernel using the NetlinkManager socket after
Wade Guthriebee87c22013-03-06 11:00:46 -0800208 // installing a handler to deal with the kernel's response to the message.
Wade Guthrie5d53d492012-11-07 09:53:31 -0800209 // TODO(wdg): Eventually, this should also include a timeout and a callback
210 // to call in case of timeout.
Wade Guthrie7347bf22013-04-30 11:21:51 -0700211 virtual bool SendControlMessage(
212 ControlNetlinkMessage *message,
213 const ControlNetlinkMessageHandler &message_handler,
214 const NetlinkAuxilliaryMessageHandler &error_handler);
215 virtual bool SendNl80211Message(
216 Nl80211Message *message,
217 const Nl80211MessageHandler &message_handler,
218 const NetlinkAuxilliaryMessageHandler &error_handler);
219
220 // Generic erroneous message handler everyone can use.
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700221 static void OnNetlinkMessageError(AuxilliaryMessageType type,
222 const NetlinkMessage *raw_message);
Wade Guthrie5d53d492012-11-07 09:53:31 -0800223
Wade Guthriebee87c22013-03-06 11:00:46 -0800224 // Uninstall the handler for a specific netlink message.
Wade Guthrief48a1952013-03-04 17:33:47 -0800225 bool RemoveMessageHandler(const NetlinkMessage &message);
Wade Guthrie0d438532012-05-18 14:18:50 -0700226
Wade Guthried6153612012-08-23 11:36:14 -0700227 // Sign-up to receive and log multicast events of a specific type (once wifi
228 // is up).
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700229 virtual bool SubscribeToEvents(const std::string &family,
230 const std::string &group);
Wade Guthried6153612012-08-23 11:36:14 -0700231
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800232 // Gets the next sequence number for a NetlinkMessage to be sent over
Wade Guthriebb9fca22013-04-10 17:21:42 -0700233 // NetlinkManager's netlink socket.
Wade Guthriebdcdaa72013-03-04 12:47:12 -0800234 uint32_t GetSequenceNumber();
235
Wade Guthrie0d438532012-05-18 14:18:50 -0700236 protected:
Wade Guthriebb9fca22013-04-10 17:21:42 -0700237 friend struct base::DefaultLazyInstanceTraits<NetlinkManager>;
Wade Guthrie0d438532012-05-18 14:18:50 -0700238
Wade Guthriebb9fca22013-04-10 17:21:42 -0700239 explicit NetlinkManager();
Wade Guthrie0d438532012-05-18 14:18:50 -0700240
241 private:
Wade Guthriebb9fca22013-04-10 17:21:42 -0700242 friend class NetlinkManagerTest;
Wade Guthrie12f113a2013-03-12 17:15:46 -0700243 friend class NetlinkMessageTest;
Darin Petkovd5818382013-01-28 16:27:07 +0100244 friend class ShillDaemonTest;
Wade Guthriebb9fca22013-04-10 17:21:42 -0700245 FRIEND_TEST(NetlinkManagerTest, AddLinkTest);
Wade Guthriebbe59f72013-05-21 08:45:39 -0700246 FRIEND_TEST(NetlinkManagerTest, BroadcastHandler);
Wade Guthriefa2100e2013-05-15 10:11:22 -0700247 FRIEND_TEST(NetlinkManagerTest, GetFamilyOneInterstitialMessage);
248 FRIEND_TEST(NetlinkManagerTest, GetFamilyTimeout);
Wade Guthriebbe59f72013-05-21 08:45:39 -0700249 FRIEND_TEST(NetlinkManagerTest, MessageHandler);
250 FRIEND_TEST(NetlinkManagerTest, MultipartMessageHandler);
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700251 FRIEND_TEST(NetlinkManagerTest, TimeoutResponseHandlers);
Wade Guthrie12f113a2013-03-12 17:15:46 -0700252 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_ASSOCIATE);
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700253 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_AUTHENTICATE);
Wade Guthrie12f113a2013-03-12 17:15:46 -0700254 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_CONNECT);
255 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DEAUTHENTICATE);
Wade Guthrie12f113a2013-03-12 17:15:46 -0700256 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DISASSOCIATE);
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700257 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_DISCONNECT);
258 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NEW_SCAN_RESULTS);
259 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NEW_STATION);
260 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_NOTIFY_CQM);
261 FRIEND_TEST(NetlinkMessageTest, Parse_NL80211_CMD_TRIGGER_SCAN);
Wade Guthrie12f113a2013-03-12 17:15:46 -0700262
Wade Guthrie7347bf22013-04-30 11:21:51 -0700263 typedef scoped_refptr<NetlinkResponseHandler> NetlinkResponseHandlerRefPtr;
Wade Guthrie0d438532012-05-18 14:18:50 -0700264
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700265 // These need to be member variables, even though they're only used once in
266 // the code, since they're needed for unittests.
267 static const long kMaximumNewFamilyWaitSeconds; // NOLINT
268 static const long kMaximumNewFamilyWaitMicroSeconds; // NOLINT
269 static const long kResponseTimeoutSeconds; // NOLINT
270 static const long kResponseTimeoutMicroSeconds; // NOLINT
Wade Guthriebee87c22013-03-06 11:00:46 -0800271
272 // Returns the file descriptor of socket used to read wifi data.
Wade Guthrie89e6cb32013-03-07 08:03:45 -0800273 int file_descriptor() const;
Wade Guthried6153612012-08-23 11:36:14 -0700274
Wade Guthrie0d438532012-05-18 14:18:50 -0700275 // EventDispatcher calls this when data is available on our socket. This
repo syncbcaa6942013-01-02 15:38:21 -0800276 // method passes each, individual, message in the input to
Wade Guthriebee87c22013-03-06 11:00:46 -0800277 // |OnNlMessageReceived|. Each part of a multipart message gets handled,
278 // individually, by this method.
repo syncbcaa6942013-01-02 15:38:21 -0800279 void OnRawNlMessageReceived(InputData *data);
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700280
281 // This method processes a message from |OnRawNlMessageReceived| by passing
Wade Guthriebb9fca22013-04-10 17:21:42 -0700282 // the message to either the NetlinkManager callback that matches the sequence
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700283 // number of the message or, if there isn't one, to all of the default
Wade Guthriebb9fca22013-04-10 17:21:42 -0700284 // NetlinkManager callbacks in |broadcast_handlers_|.
repo syncbcaa6942013-01-02 15:38:21 -0800285 void OnNlMessageReceived(nlmsghdr *msg);
286
287 // Called by InputHandler on exceptional events.
288 void OnReadError(const Error &error);
Wade Guthrie0d438532012-05-18 14:18:50 -0700289
Wade Guthriebee87c22013-03-06 11:00:46 -0800290 // Just for tests, this method turns off WiFi and clears the subscribed
291 // events list. If |full| is true, also clears state set by Init.
Darin Petkovd5818382013-01-28 16:27:07 +0100292 void Reset(bool full);
Wade Guthried6153612012-08-23 11:36:14 -0700293
Wade Guthriebee87c22013-03-06 11:00:46 -0800294 // Handles a CTRL_CMD_NEWFAMILY message from the kernel.
Wade Guthrie7347bf22013-04-30 11:21:51 -0700295 void OnNewFamilyMessage(const ControlNetlinkMessage &message);
296
297 // Sends a netlink message to the kernel using the NetlinkManager socket after
298 // installing a handler to deal with the kernel's response to the message.
299 // Adds a serial number to |message| before it is sent.
300 bool SendMessageInternal(
301 NetlinkMessage *message,
302 NetlinkResponseHandler *message_wrapper); // Passes ownership.
Wade Guthriebee87c22013-03-06 11:00:46 -0800303
Wade Guthriebb9fca22013-04-10 17:21:42 -0700304 // NetlinkManager Handlers, OnRawNlMessageReceived invokes each of these
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700305 // User-supplied callback object when _it_ gets called to read libnl data.
Wade Guthrie71cb0a72013-02-27 10:27:18 -0800306 std::list<NetlinkMessageHandler> broadcast_handlers_;
Wade Guthrie0d438532012-05-18 14:18:50 -0700307
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700308 // Message-specific callbacks, mapped by message ID.
Wade Guthrie7347bf22013-04-30 11:21:51 -0700309 std::map<uint32_t, NetlinkResponseHandlerRefPtr> message_handlers_;
Wade Guthrie0d438532012-05-18 14:18:50 -0700310
Wade Guthrie0d438532012-05-18 14:18:50 -0700311 // Hooks needed to be called by shill's EventDispatcher.
312 EventDispatcher *dispatcher_;
Wade Guthriebb9fca22013-04-10 17:21:42 -0700313 base::WeakPtrFactory<NetlinkManager> weak_ptr_factory_;
repo syncbcaa6942013-01-02 15:38:21 -0800314 base::Callback<void(InputData *)> dispatcher_callback_;
Wade Guthrie0d438532012-05-18 14:18:50 -0700315 scoped_ptr<IOHandler> dispatcher_handler_;
316
Wade Guthriecc53f232013-03-05 13:22:23 -0800317 NetlinkSocket *sock_;
Wade Guthriebee87c22013-03-06 11:00:46 -0800318 std::map<const std::string, MessageType> message_types_;
Wade Guthrie12f113a2013-03-12 17:15:46 -0700319 NetlinkMessageFactory message_factory_;
Wade Guthriefa2100e2013-05-15 10:11:22 -0700320 Time *time_;
Wade Guthrie0d438532012-05-18 14:18:50 -0700321
Wade Guthriebb9fca22013-04-10 17:21:42 -0700322 DISALLOW_COPY_AND_ASSIGN(NetlinkManager);
Wade Guthrie0d438532012-05-18 14:18:50 -0700323};
324
Wade Guthrie0d438532012-05-18 14:18:50 -0700325} // namespace shill
326
Wade Guthriebb9fca22013-04-10 17:21:42 -0700327#endif // SHILL_NETLINK_MANAGER_H_