blob: 01e27e8671e575e851334c589971ef648061052b [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
repo syncbcaa6942013-01-02 15:38:21 -080017#include "shill/error.h"
Wade Guthrie0d438532012-05-18 14:18:50 -070018#include "shill/io_handler.h"
19#include "shill/logging.h"
repo syncdc085c82012-12-28 08:54:41 -080020#include "shill/nl80211_message.h"
Wade Guthrie0d438532012-05-18 14:18:50 -070021#include "shill/nl80211_socket.h"
22#include "shill/scope_logger.h"
Wade Guthrie0d438532012-05-18 14:18:50 -070023
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),
repo syncbcaa6942013-01-02 15:38:21 -080041 dispatcher_callback_(Bind(&Config80211::OnRawNlMessageReceived,
42 weak_ptr_factory_.GetWeakPtr())),
Wade Guthrie0d438532012-05-18 14:18:50 -070043 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
Darin Petkovd5818382013-01-28 16:27:07 +010057void Config80211::Reset(bool full) {
Wade Guthried6153612012-08-23 11:36:14 -070058 wifi_state_ = kWifiDown;
59 subscribed_events_.clear();
Wade Guthrieb1ec8602012-10-18 17:26:14 -070060 ClearBroadcastCallbacks();
Darin Petkovd5818382013-01-28 16:27:07 +010061 if (full) {
62 dispatcher_ = NULL;
63 delete sock_;
64 sock_ = NULL;
65 }
Wade Guthried6153612012-08-23 11:36:14 -070066}
67
Wade Guthrie0d438532012-05-18 14:18:50 -070068bool Config80211::Init(EventDispatcher *dispatcher) {
69 if (!sock_) {
70 sock_ = new Nl80211Socket;
71 if (!sock_) {
72 LOG(ERROR) << "No memory";
73 return false;
74 }
75
76 if (!sock_->Init()) {
77 return false;
78 }
Wade Guthrie5d53d492012-11-07 09:53:31 -080079 // 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
Wade Guthrie0d438532012-05-18 14:18:50 -070093 dispatcher_ = dispatcher;
Wade Guthrie0d438532012-05-18 14:18:50 -070094 return true;
95}
96
Wade Guthrieb1ec8602012-10-18 17:26:14 -070097bool Config80211::AddBroadcastCallback(const Callback &callback) {
98 list<Callback>::iterator i;
99 if (FindBroadcastCallback(callback)) {
100 LOG(WARNING) << "Trying to re-add a callback";
101 return false; // Should only be one copy in the list.
102 }
103 if (callback.is_null()) {
104 LOG(WARNING) << "Trying to add a NULL callback";
105 return false;
106 }
107 // And add the callback to the list.
108 SLOG(WiFi, 3) << "Config80211::" << __func__ << " - adding callback";
109 broadcast_callbacks_.push_back(callback);
110 return true;
111}
112
113bool Config80211::RemoveBroadcastCallback(const Callback &callback) {
114 list<Callback>::iterator i;
115 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
116 if ((*i).Equals(callback)) {
117 broadcast_callbacks_.erase(i);
118 // Should only be one copy in the list so we don't have to continue
119 // looking for another one.
120 return true;
121 }
122 }
123 LOG(WARNING) << "Callback not found.";
124 return false;
125}
126
127bool Config80211::FindBroadcastCallback(const Callback &callback) const {
128 list<Callback>::const_iterator i;
129 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
130 if ((*i).Equals(callback)) {
131 return true;
132 }
133 }
134 return false;
135}
136
137void Config80211::ClearBroadcastCallbacks() {
138 broadcast_callbacks_.clear();
139}
140
repo syncdc085c82012-12-28 08:54:41 -0800141bool Config80211::SendMessage(Nl80211Message *message,
Wade Guthrie5d53d492012-11-07 09:53:31 -0800142 const Callback &callback) {
143 if (!message) {
144 LOG(ERROR) << "Message is NULL.";
145 return false;
146 }
repo syncdc085c82012-12-28 08:54:41 -0800147 uint32 sequence_number = message->sequence_number();
Christopher Wiley393b93f2012-11-08 17:30:58 -0800148 if (!sequence_number) {
repo syncdc085c82012-12-28 08:54:41 -0800149 sequence_number = sock_->GetSequenceNumber();
150 message->set_sequence_number(sequence_number);
151 }
152 if (!sock_->SendMessage(message)) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800153 LOG(ERROR) << "Failed to send nl80211 message.";
Wade Guthrie5d53d492012-11-07 09:53:31 -0800154 return false;
155 }
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700156 if (callback.is_null()) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800157 LOG(INFO) << "Callback for message was null.";
158 return true;
159 }
160 if (ContainsKey(message_callbacks_, sequence_number)) {
161 LOG(ERROR) << "Sent message, but already had a callback for this message?";
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700162 return false;
163 }
Christopher Wiley393b93f2012-11-08 17:30:58 -0800164 message_callbacks_[sequence_number] = callback;
165 LOG(INFO) << "Sent nl80211 message with sequence number: " << sequence_number;
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700166 return true;
167}
168
repo syncdc085c82012-12-28 08:54:41 -0800169bool Config80211::RemoveMessageCallback(const Nl80211Message &message) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800170 if (!ContainsKey(message_callbacks_, message.sequence_number())) {
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700171 return false;
172 }
Christopher Wiley393b93f2012-11-08 17:30:58 -0800173 message_callbacks_.erase(message.sequence_number());
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700174 return true;
175}
176
Wade Guthrie0d438532012-05-18 14:18:50 -0700177// static
178bool Config80211::GetEventTypeString(EventType type, string *value) {
179 if (!value) {
180 LOG(ERROR) << "NULL |value|";
181 return false;
182 }
183 if (!event_types_) {
184 LOG(ERROR) << "NULL |event_types_|";
185 return false;
186 }
187
Wade Guthried6153612012-08-23 11:36:14 -0700188 EventTypeStrings::iterator match = (*event_types_).find(type);
Wade Guthrie0d438532012-05-18 14:18:50 -0700189 if (match == (*event_types_).end()) {
190 LOG(ERROR) << "Event type " << type << " not found";
191 return false;
192 }
193 *value = match->second;
194 return true;
195}
196
Wade Guthried6153612012-08-23 11:36:14 -0700197void Config80211::SetWifiState(WifiState new_state) {
198 if (wifi_state_ == new_state) {
199 return;
200 }
201
Wade Guthrie5d53d492012-11-07 09:53:31 -0800202 if (!sock_) {
203 LOG(ERROR) << "Config80211::Init needs to be called before this";
204 return;
205 }
206
Wade Guthried6153612012-08-23 11:36:14 -0700207 if (new_state == kWifiUp) {
repo syncbcaa6942013-01-02 15:38:21 -0800208 // Install ourselves in the shill mainloop so we receive messages on the
209 // nl80211 socket.
210 if (dispatcher_) {
211 dispatcher_handler_.reset(dispatcher_->CreateInputHandler(
212 GetFd(),
213 dispatcher_callback_,
214 Bind(&Config80211::OnReadError, weak_ptr_factory_.GetWeakPtr())));
215 }
216
217 // If we're newly-up, subscribe to all the event types that have been
218 // requested.
Wade Guthried6153612012-08-23 11:36:14 -0700219 SubscribedEvents::const_iterator i;
220 for (i = subscribed_events_.begin(); i != subscribed_events_.end(); ++i) {
Wade Guthried6153612012-08-23 11:36:14 -0700221 ActuallySubscribeToEvents(*i);
222 }
223 }
224 wifi_state_ = new_state;
225}
226
Wade Guthrie0d438532012-05-18 14:18:50 -0700227bool Config80211::SubscribeToEvents(EventType type) {
Wade Guthried6153612012-08-23 11:36:14 -0700228 bool it_worked = true;
229 if (!ContainsKey(subscribed_events_, type)) {
230 if (wifi_state_ == kWifiUp) {
231 it_worked = ActuallySubscribeToEvents(type);
232 }
233 // |subscribed_events_| is a list of events to which we want to subscribe
234 // when wifi comes up (including when it comes _back_ up after it goes
235 // down sometime in the future).
236 subscribed_events_.insert(type);
237 }
238 return it_worked;
239}
240
241bool Config80211::ActuallySubscribeToEvents(EventType type) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700242 string group_name;
243
244 if (!GetEventTypeString(type, &group_name)) {
245 return false;
246 }
247 if (!sock_->AddGroupMembership(group_name)) {
248 return false;
249 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700250 return true;
251}
252
repo syncbcaa6942013-01-02 15:38:21 -0800253void Config80211::OnRawNlMessageReceived(InputData *data) {
254 if (!data) {
255 LOG(ERROR) << __func__ << "() called with null header.";
256 return;
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700257 }
repo syncbcaa6942013-01-02 15:38:21 -0800258 unsigned char *buf = data->buf;
259 unsigned char *end = buf + data->len;
260 while (buf < end) {
261 nlmsghdr *msg = reinterpret_cast<nlmsghdr *>(buf);
262 // Discard the message if there're not enough bytes to a) tell the code how
263 // much space is in the message (i.e., to access nlmsg_len) or b) to hold
264 // the entire message. The odd calculation is there to keep the code from
265 // potentially calculating an illegal address (causes a segfault on some
266 // architectures).
267 size_t bytes_left = end - buf;
268 if (((bytes_left < (offsetof(nlmsghdr, nlmsg_len) +
Liam McLoughlinf4baef22012-08-01 19:08:25 -0700269 sizeof(msg->nlmsg_len))) ||
repo syncbcaa6942013-01-02 15:38:21 -0800270 (bytes_left < msg->nlmsg_len))) {
271 LOG(ERROR) << "Discarding incomplete message.";
272 return;
273 }
274 OnNlMessageReceived(msg);
275 buf += msg->nlmsg_len;
276 }
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700277}
Wade Guthrie0d438532012-05-18 14:18:50 -0700278
repo syncbcaa6942013-01-02 15:38:21 -0800279void Config80211::OnNlMessageReceived(nlmsghdr *msg) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800280 if (!msg) {
281 LOG(ERROR) << __func__ << "() called with null header.";
repo syncbcaa6942013-01-02 15:38:21 -0800282 return;
Christopher Wiley393b93f2012-11-08 17:30:58 -0800283 }
284 const uint32 sequence_number = msg->nlmsg_seq;
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700285 SLOG(WiFi, 3) << "\t Entering " << __func__
repo syncbcaa6942013-01-02 15:38:21 -0800286 << " (msg:" << sequence_number << ")";
repo syncdc085c82012-12-28 08:54:41 -0800287 scoped_ptr<Nl80211Message> message(Nl80211MessageFactory::CreateMessage(msg));
Wade Guthrie0d438532012-05-18 14:18:50 -0700288 if (message == NULL) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700289 SLOG(WiFi, 3) << __func__ << "(msg:NULL)";
repo syncbcaa6942013-01-02 15:38:21 -0800290 return; // Skip current message, continue parsing buffer.
Christopher Wiley393b93f2012-11-08 17:30:58 -0800291 }
292 // Call (then erase) any message-specific callback.
repo syncbcaa6942013-01-02 15:38:21 -0800293 // TODO(wdg): Support multi-part messages; don't delete callback until last
294 // part appears.
Christopher Wiley393b93f2012-11-08 17:30:58 -0800295 if (ContainsKey(message_callbacks_, sequence_number)) {
296 SLOG(WiFi, 3) << "found message-specific callback";
297 if (message_callbacks_[sequence_number].is_null()) {
298 LOG(ERROR) << "Callback exists but is NULL for ID " << sequence_number;
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700299 } else {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800300 message_callbacks_[sequence_number].Run(*message);
301 }
302 message_callbacks_.erase(sequence_number);
303 } else {
repo syncbcaa6942013-01-02 15:38:21 -0800304 list<Callback>::const_iterator i = broadcast_callbacks_.begin();
Christopher Wiley393b93f2012-11-08 17:30:58 -0800305 while (i != broadcast_callbacks_.end()) {
repo syncbcaa6942013-01-02 15:38:21 -0800306 SLOG(WiFi, 3) << " " << __func__ << " - calling callback";
307 i->Run(*message);
308 ++i;
Wade Guthrie0d438532012-05-18 14:18:50 -0700309 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700310 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700311}
312
repo syncbcaa6942013-01-02 15:38:21 -0800313void Config80211::OnReadError(const Error &error) {
314 // TODO(wdg): When config80211 is used for scan, et al., this should either be
315 // LOG(FATAL) or the code should properly deal with errors, e.g., dropped
316 // messages due to the socket buffer being full.
317 LOG(ERROR) << "Config80211's netlink Socket read returns error: "
318 << error.message();
319}
320
321
Wade Guthrie0d438532012-05-18 14:18:50 -0700322} // namespace shill.