blob: 320e9cc6ae3c3e87c8af766689231d01516cb23e [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
5#include "shill/config80211.h"
6
7#include <ctype.h>
Wade Guthrie0d438532012-05-18 14:18:50 -07008#include <netlink/msg.h>
9
10#include <map>
11#include <sstream>
12#include <string>
13
14#include <base/memory/weak_ptr.h>
Wade Guthried6153612012-08-23 11:36:14 -070015#include <base/stl_util.h>
Wade Guthrie0d438532012-05-18 14:18:50 -070016
17#include "shill/io_handler.h"
Wade Guthrie5d53d492012-11-07 09:53:31 -080018#include "shill/kernel_bound_nlmessage.h"
Wade Guthrie0d438532012-05-18 14:18:50 -070019#include "shill/logging.h"
20#include "shill/nl80211_socket.h"
21#include "shill/scope_logger.h"
22#include "shill/user_bound_nlmessage.h"
23
24using base::Bind;
25using base::LazyInstance;
Wade Guthrieb1ec8602012-10-18 17:26:14 -070026using std::list;
Wade Guthrie0d438532012-05-18 14:18:50 -070027using std::string;
28
29namespace shill {
30
31namespace {
32LazyInstance<Config80211> g_config80211 = LAZY_INSTANCE_INITIALIZER;
Wade Guthrie0d438532012-05-18 14:18:50 -070033} // namespace
34
Wade Guthried6153612012-08-23 11:36:14 -070035Config80211::EventTypeStrings *Config80211::event_types_ = NULL;
Wade Guthrie0d438532012-05-18 14:18:50 -070036
37Config80211::Config80211()
Wade Guthried6153612012-08-23 11:36:14 -070038 : wifi_state_(kWifiDown),
39 dispatcher_(NULL),
Wade Guthrie0d438532012-05-18 14:18:50 -070040 weak_ptr_factory_(this),
41 dispatcher_callback_(Bind(&Config80211::HandleIncomingEvents,
42 weak_ptr_factory_.GetWeakPtr())),
43 sock_(NULL) {
44}
45
46Config80211::~Config80211() {
47 // Since Config80211 is a singleton, it should be safe to delete a static
48 // member.
49 delete event_types_;
50 event_types_ = NULL;
51}
52
53Config80211 *Config80211::GetInstance() {
54 return g_config80211.Pointer();
55}
56
Wade Guthried6153612012-08-23 11:36:14 -070057void Config80211::Reset() {
58 wifi_state_ = kWifiDown;
59 subscribed_events_.clear();
Wade Guthrieb1ec8602012-10-18 17:26:14 -070060 ClearBroadcastCallbacks();
Wade Guthried6153612012-08-23 11:36:14 -070061}
62
Wade Guthrie0d438532012-05-18 14:18:50 -070063bool Config80211::Init(EventDispatcher *dispatcher) {
64 if (!sock_) {
65 sock_ = new Nl80211Socket;
66 if (!sock_) {
67 LOG(ERROR) << "No memory";
68 return false;
69 }
70
71 if (!sock_->Init()) {
72 return false;
73 }
Wade Guthrie5d53d492012-11-07 09:53:31 -080074
75 // Install the global NetLink Callback.
76 sock_->SetNetlinkCallback(OnRawNlMessageReceived,
77 static_cast<void *>(this));
78
79 // Don't make libnl do the sequence checking (because it'll not like
80 // the broadcast messages for which we'll eventually ask). We'll do all the
81 // sequence checking we need.
82 sock_->DisableSequenceChecking();
Wade Guthrie0d438532012-05-18 14:18:50 -070083 }
84
85 if (!event_types_) {
Wade Guthried6153612012-08-23 11:36:14 -070086 event_types_ = new EventTypeStrings;
Wade Guthrie0d438532012-05-18 14:18:50 -070087 (*event_types_)[Config80211::kEventTypeConfig] = "config";
88 (*event_types_)[Config80211::kEventTypeScan] = "scan";
89 (*event_types_)[Config80211::kEventTypeRegulatory] = "regulatory";
90 (*event_types_)[Config80211::kEventTypeMlme] = "mlme";
91 }
92
93 // Install ourselves in the shill mainloop so we receive messages on the
94 // nl80211 socket.
95 dispatcher_ = dispatcher;
96 if (dispatcher_) {
97 dispatcher_handler_.reset(
98 dispatcher_->CreateReadyHandler(GetFd(),
99 IOHandler::kModeInput,
100 dispatcher_callback_));
101 }
102 return true;
103}
104
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700105bool Config80211::AddBroadcastCallback(const Callback &callback) {
106 list<Callback>::iterator i;
107 if (FindBroadcastCallback(callback)) {
108 LOG(WARNING) << "Trying to re-add a callback";
109 return false; // Should only be one copy in the list.
110 }
111 if (callback.is_null()) {
112 LOG(WARNING) << "Trying to add a NULL callback";
113 return false;
114 }
115 // And add the callback to the list.
116 SLOG(WiFi, 3) << "Config80211::" << __func__ << " - adding callback";
117 broadcast_callbacks_.push_back(callback);
118 return true;
119}
120
121bool Config80211::RemoveBroadcastCallback(const Callback &callback) {
122 list<Callback>::iterator i;
123 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
124 if ((*i).Equals(callback)) {
125 broadcast_callbacks_.erase(i);
126 // Should only be one copy in the list so we don't have to continue
127 // looking for another one.
128 return true;
129 }
130 }
131 LOG(WARNING) << "Callback not found.";
132 return false;
133}
134
135bool Config80211::FindBroadcastCallback(const Callback &callback) const {
136 list<Callback>::const_iterator i;
137 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
138 if ((*i).Equals(callback)) {
139 return true;
140 }
141 }
142 return false;
143}
144
145void Config80211::ClearBroadcastCallbacks() {
146 broadcast_callbacks_.clear();
147}
148
Wade Guthrie5d53d492012-11-07 09:53:31 -0800149bool Config80211::SendMessage(KernelBoundNlMessage *message,
150 const Callback &callback) {
151 if (!message) {
152 LOG(ERROR) << "Message is NULL.";
153 return false;
154 }
Christopher Wiley393b93f2012-11-08 17:30:58 -0800155 uint32 sequence_number = sock_->Send(message);
156 if (!sequence_number) {
157 LOG(ERROR) << "Failed to send nl80211 message.";
Wade Guthrie5d53d492012-11-07 09:53:31 -0800158 return false;
159 }
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700160 if (callback.is_null()) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800161 LOG(INFO) << "Callback for message was null.";
162 return true;
163 }
164 if (ContainsKey(message_callbacks_, sequence_number)) {
165 LOG(ERROR) << "Sent message, but already had a callback for this message?";
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700166 return false;
167 }
Christopher Wiley393b93f2012-11-08 17:30:58 -0800168 message_callbacks_[sequence_number] = callback;
169 LOG(INFO) << "Sent nl80211 message with sequence number: " << sequence_number;
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700170 return true;
171}
172
Christopher Wiley393b93f2012-11-08 17:30:58 -0800173bool Config80211::RemoveMessageCallback(const KernelBoundNlMessage &message) {
174 if (!ContainsKey(message_callbacks_, message.sequence_number())) {
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700175 return false;
176 }
Christopher Wiley393b93f2012-11-08 17:30:58 -0800177 message_callbacks_.erase(message.sequence_number());
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700178 return true;
179}
180
Wade Guthrie0d438532012-05-18 14:18:50 -0700181// static
182bool Config80211::GetEventTypeString(EventType type, string *value) {
183 if (!value) {
184 LOG(ERROR) << "NULL |value|";
185 return false;
186 }
187 if (!event_types_) {
188 LOG(ERROR) << "NULL |event_types_|";
189 return false;
190 }
191
Wade Guthried6153612012-08-23 11:36:14 -0700192 EventTypeStrings::iterator match = (*event_types_).find(type);
Wade Guthrie0d438532012-05-18 14:18:50 -0700193 if (match == (*event_types_).end()) {
194 LOG(ERROR) << "Event type " << type << " not found";
195 return false;
196 }
197 *value = match->second;
198 return true;
199}
200
Wade Guthried6153612012-08-23 11:36:14 -0700201void Config80211::SetWifiState(WifiState new_state) {
202 if (wifi_state_ == new_state) {
203 return;
204 }
205
Wade Guthrie5d53d492012-11-07 09:53:31 -0800206 if (!sock_) {
207 LOG(ERROR) << "Config80211::Init needs to be called before this";
208 return;
209 }
210
Wade Guthried6153612012-08-23 11:36:14 -0700211 // If we're newly-up, subscribe to all the event types that have been
212 // requested.
213 if (new_state == kWifiUp) {
Wade Guthrie5d53d492012-11-07 09:53:31 -0800214 // Install the global NetLink Callback.
215 sock_->SetNetlinkCallback(OnRawNlMessageReceived,
216 static_cast<void *>(this));
Wade Guthried6153612012-08-23 11:36:14 -0700217 SubscribedEvents::const_iterator i;
218 for (i = subscribed_events_.begin(); i != subscribed_events_.end(); ++i) {
Wade Guthried6153612012-08-23 11:36:14 -0700219 ActuallySubscribeToEvents(*i);
220 }
221 }
222 wifi_state_ = new_state;
223}
224
Wade Guthrie0d438532012-05-18 14:18:50 -0700225bool Config80211::SubscribeToEvents(EventType type) {
Wade Guthried6153612012-08-23 11:36:14 -0700226 bool it_worked = true;
227 if (!ContainsKey(subscribed_events_, type)) {
228 if (wifi_state_ == kWifiUp) {
229 it_worked = ActuallySubscribeToEvents(type);
230 }
231 // |subscribed_events_| is a list of events to which we want to subscribe
232 // when wifi comes up (including when it comes _back_ up after it goes
233 // down sometime in the future).
234 subscribed_events_.insert(type);
235 }
236 return it_worked;
237}
238
239bool Config80211::ActuallySubscribeToEvents(EventType type) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700240 string group_name;
241
242 if (!GetEventTypeString(type, &group_name)) {
243 return false;
244 }
245 if (!sock_->AddGroupMembership(group_name)) {
246 return false;
247 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700248 return true;
249}
250
251void Config80211::HandleIncomingEvents(int unused_fd) {
252 sock_->GetMessages();
253}
254
255// NOTE: the "struct nl_msg" declaration, below, is a complete fabrication
256// (but one consistent with the nl_socket_modify_cb call to which
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700257// |OnRawNlMessageReceived| is a parameter). |raw_message| is actually a
Wade Guthrie0d438532012-05-18 14:18:50 -0700258// "struct sk_buff" but that data type is only visible in the kernel. We'll
259// scrub this erroneous datatype with the "nlmsg_hdr" call, below, which
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700260// extracts an nlmsghdr pointer from |raw_message|. We'll, then, pass this to
261// a separate method, |OnNlMessageReceived|, to make testing easier.
Wade Guthrie0d438532012-05-18 14:18:50 -0700262
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700263// static
264int Config80211::OnRawNlMessageReceived(struct nl_msg *raw_message,
265 void *void_config80211) {
266 if (!void_config80211) {
267 LOG(WARNING) << "NULL config80211 parameter";
268 return NL_SKIP; // Skip current message, continue parsing buffer.
269 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700270
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700271 Config80211 *config80211 = static_cast<Config80211 *>(void_config80211);
272 SLOG(WiFi, 3) << " " << __func__ << " calling OnNlMessageReceived";
273 return config80211->OnNlMessageReceived(nlmsg_hdr(raw_message));
274}
Wade Guthrie0d438532012-05-18 14:18:50 -0700275
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700276int Config80211::OnNlMessageReceived(nlmsghdr *msg) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800277 if (!msg) {
278 LOG(ERROR) << __func__ << "() called with null header.";
279 return NL_SKIP;
280 }
281 const uint32 sequence_number = msg->nlmsg_seq;
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700282 SLOG(WiFi, 3) << "\t Entering " << __func__
Christopher Wiley393b93f2012-11-08 17:30:58 -0800283 << "( msg:" << sequence_number << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700284 scoped_ptr<UserBoundNlMessage> message(
285 UserBoundNlMessageFactory::CreateMessage(msg));
286 if (message == NULL) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700287 SLOG(WiFi, 3) << __func__ << "(msg:NULL)";
Christopher Wiley393b93f2012-11-08 17:30:58 -0800288 return NL_SKIP; // Skip current message, continue parsing buffer.
289 }
290 // Call (then erase) any message-specific callback.
291 if (ContainsKey(message_callbacks_, sequence_number)) {
292 SLOG(WiFi, 3) << "found message-specific callback";
293 if (message_callbacks_[sequence_number].is_null()) {
294 LOG(ERROR) << "Callback exists but is NULL for ID " << sequence_number;
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700295 } else {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800296 message_callbacks_[sequence_number].Run(*message);
297 }
298 message_callbacks_.erase(sequence_number);
299 } else {
300 list<Callback>::iterator i = broadcast_callbacks_.begin();
301 while (i != broadcast_callbacks_.end()) {
302 SLOG(WiFi, 3) << "found a broadcast callback";
303 if (i->is_null()) {
304 i = broadcast_callbacks_.erase(i);
305 } else {
306 SLOG(WiFi, 3) << " " << __func__ << " - calling callback";
307 i->Run(*message);
308 ++i;
Wade Guthrie0d438532012-05-18 14:18:50 -0700309 }
310 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700311 }
312
Wade Guthrie0d438532012-05-18 14:18:50 -0700313 return NL_SKIP; // Skip current message, continue parsing buffer.
314}
315
Wade Guthrie0d438532012-05-18 14:18:50 -0700316} // namespace shill.