blob: 7bcaa4a3fe3ca2eeccb182534ecb4dfb7d500e4c [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
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 // Don't make libnl do the sequence checking (because it'll not like
75 // the broadcast messages for which we'll eventually ask). We'll do all the
76 // sequence checking we need.
77 sock_->DisableSequenceChecking();
Wade Guthrie0d438532012-05-18 14:18:50 -070078 }
79
80 if (!event_types_) {
Wade Guthried6153612012-08-23 11:36:14 -070081 event_types_ = new EventTypeStrings;
Wade Guthrie0d438532012-05-18 14:18:50 -070082 (*event_types_)[Config80211::kEventTypeConfig] = "config";
83 (*event_types_)[Config80211::kEventTypeScan] = "scan";
84 (*event_types_)[Config80211::kEventTypeRegulatory] = "regulatory";
85 (*event_types_)[Config80211::kEventTypeMlme] = "mlme";
86 }
87
Wade Guthrie0d438532012-05-18 14:18:50 -070088 dispatcher_ = dispatcher;
Wade Guthrie0d438532012-05-18 14:18:50 -070089 return true;
90}
91
Wade Guthrieb1ec8602012-10-18 17:26:14 -070092bool Config80211::AddBroadcastCallback(const Callback &callback) {
93 list<Callback>::iterator i;
94 if (FindBroadcastCallback(callback)) {
95 LOG(WARNING) << "Trying to re-add a callback";
96 return false; // Should only be one copy in the list.
97 }
98 if (callback.is_null()) {
99 LOG(WARNING) << "Trying to add a NULL callback";
100 return false;
101 }
102 // And add the callback to the list.
103 SLOG(WiFi, 3) << "Config80211::" << __func__ << " - adding callback";
104 broadcast_callbacks_.push_back(callback);
105 return true;
106}
107
108bool Config80211::RemoveBroadcastCallback(const Callback &callback) {
109 list<Callback>::iterator i;
110 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
111 if ((*i).Equals(callback)) {
112 broadcast_callbacks_.erase(i);
113 // Should only be one copy in the list so we don't have to continue
114 // looking for another one.
115 return true;
116 }
117 }
118 LOG(WARNING) << "Callback not found.";
119 return false;
120}
121
122bool Config80211::FindBroadcastCallback(const Callback &callback) const {
123 list<Callback>::const_iterator i;
124 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
125 if ((*i).Equals(callback)) {
126 return true;
127 }
128 }
129 return false;
130}
131
132void Config80211::ClearBroadcastCallbacks() {
133 broadcast_callbacks_.clear();
134}
135
repo syncdc085c82012-12-28 08:54:41 -0800136bool Config80211::SendMessage(Nl80211Message *message,
Wade Guthrie5d53d492012-11-07 09:53:31 -0800137 const Callback &callback) {
138 if (!message) {
139 LOG(ERROR) << "Message is NULL.";
140 return false;
141 }
repo syncdc085c82012-12-28 08:54:41 -0800142 uint32 sequence_number = message->sequence_number();
Christopher Wiley393b93f2012-11-08 17:30:58 -0800143 if (!sequence_number) {
repo syncdc085c82012-12-28 08:54:41 -0800144 sequence_number = sock_->GetSequenceNumber();
145 message->set_sequence_number(sequence_number);
146 }
147 if (!sock_->SendMessage(message)) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800148 LOG(ERROR) << "Failed to send nl80211 message.";
Wade Guthrie5d53d492012-11-07 09:53:31 -0800149 return false;
150 }
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700151 if (callback.is_null()) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800152 LOG(INFO) << "Callback for message was null.";
153 return true;
154 }
155 if (ContainsKey(message_callbacks_, sequence_number)) {
156 LOG(ERROR) << "Sent message, but already had a callback for this message?";
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700157 return false;
158 }
Christopher Wiley393b93f2012-11-08 17:30:58 -0800159 message_callbacks_[sequence_number] = callback;
160 LOG(INFO) << "Sent nl80211 message with sequence number: " << sequence_number;
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700161 return true;
162}
163
repo syncdc085c82012-12-28 08:54:41 -0800164bool Config80211::RemoveMessageCallback(const Nl80211Message &message) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800165 if (!ContainsKey(message_callbacks_, message.sequence_number())) {
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700166 return false;
167 }
Christopher Wiley393b93f2012-11-08 17:30:58 -0800168 message_callbacks_.erase(message.sequence_number());
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700169 return true;
170}
171
Wade Guthrie0d438532012-05-18 14:18:50 -0700172// static
173bool Config80211::GetEventTypeString(EventType type, string *value) {
174 if (!value) {
175 LOG(ERROR) << "NULL |value|";
176 return false;
177 }
178 if (!event_types_) {
179 LOG(ERROR) << "NULL |event_types_|";
180 return false;
181 }
182
Wade Guthried6153612012-08-23 11:36:14 -0700183 EventTypeStrings::iterator match = (*event_types_).find(type);
Wade Guthrie0d438532012-05-18 14:18:50 -0700184 if (match == (*event_types_).end()) {
185 LOG(ERROR) << "Event type " << type << " not found";
186 return false;
187 }
188 *value = match->second;
189 return true;
190}
191
Wade Guthried6153612012-08-23 11:36:14 -0700192void Config80211::SetWifiState(WifiState new_state) {
193 if (wifi_state_ == new_state) {
194 return;
195 }
196
Wade Guthrie5d53d492012-11-07 09:53:31 -0800197 if (!sock_) {
198 LOG(ERROR) << "Config80211::Init needs to be called before this";
199 return;
200 }
201
Wade Guthried6153612012-08-23 11:36:14 -0700202 if (new_state == kWifiUp) {
repo syncbcaa6942013-01-02 15:38:21 -0800203 // Install ourselves in the shill mainloop so we receive messages on the
204 // nl80211 socket.
205 if (dispatcher_) {
206 dispatcher_handler_.reset(dispatcher_->CreateInputHandler(
207 GetFd(),
208 dispatcher_callback_,
209 Bind(&Config80211::OnReadError, weak_ptr_factory_.GetWeakPtr())));
210 }
211
212 // If we're newly-up, subscribe to all the event types that have been
213 // requested.
Wade Guthried6153612012-08-23 11:36:14 -0700214 SubscribedEvents::const_iterator i;
215 for (i = subscribed_events_.begin(); i != subscribed_events_.end(); ++i) {
Wade Guthried6153612012-08-23 11:36:14 -0700216 ActuallySubscribeToEvents(*i);
217 }
218 }
219 wifi_state_ = new_state;
220}
221
Wade Guthrie0d438532012-05-18 14:18:50 -0700222bool Config80211::SubscribeToEvents(EventType type) {
Wade Guthried6153612012-08-23 11:36:14 -0700223 bool it_worked = true;
224 if (!ContainsKey(subscribed_events_, type)) {
225 if (wifi_state_ == kWifiUp) {
226 it_worked = ActuallySubscribeToEvents(type);
227 }
228 // |subscribed_events_| is a list of events to which we want to subscribe
229 // when wifi comes up (including when it comes _back_ up after it goes
230 // down sometime in the future).
231 subscribed_events_.insert(type);
232 }
233 return it_worked;
234}
235
236bool Config80211::ActuallySubscribeToEvents(EventType type) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700237 string group_name;
238
239 if (!GetEventTypeString(type, &group_name)) {
240 return false;
241 }
242 if (!sock_->AddGroupMembership(group_name)) {
243 return false;
244 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700245 return true;
246}
247
repo syncbcaa6942013-01-02 15:38:21 -0800248void Config80211::OnRawNlMessageReceived(InputData *data) {
249 if (!data) {
250 LOG(ERROR) << __func__ << "() called with null header.";
251 return;
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700252 }
repo syncbcaa6942013-01-02 15:38:21 -0800253 unsigned char *buf = data->buf;
254 unsigned char *end = buf + data->len;
255 while (buf < end) {
256 nlmsghdr *msg = reinterpret_cast<nlmsghdr *>(buf);
257 // Discard the message if there're not enough bytes to a) tell the code how
258 // much space is in the message (i.e., to access nlmsg_len) or b) to hold
259 // the entire message. The odd calculation is there to keep the code from
260 // potentially calculating an illegal address (causes a segfault on some
261 // architectures).
262 size_t bytes_left = end - buf;
263 if (((bytes_left < (offsetof(nlmsghdr, nlmsg_len) +
264 sizeof(nlmsghdr::nlmsg_len))) ||
265 (bytes_left < msg->nlmsg_len))) {
266 LOG(ERROR) << "Discarding incomplete message.";
267 return;
268 }
269 OnNlMessageReceived(msg);
270 buf += msg->nlmsg_len;
271 }
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700272}
Wade Guthrie0d438532012-05-18 14:18:50 -0700273
repo syncbcaa6942013-01-02 15:38:21 -0800274void Config80211::OnNlMessageReceived(nlmsghdr *msg) {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800275 if (!msg) {
276 LOG(ERROR) << __func__ << "() called with null header.";
repo syncbcaa6942013-01-02 15:38:21 -0800277 return;
Christopher Wiley393b93f2012-11-08 17:30:58 -0800278 }
279 const uint32 sequence_number = msg->nlmsg_seq;
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700280 SLOG(WiFi, 3) << "\t Entering " << __func__
repo syncbcaa6942013-01-02 15:38:21 -0800281 << " (msg:" << sequence_number << ")";
repo syncdc085c82012-12-28 08:54:41 -0800282 scoped_ptr<Nl80211Message> message(Nl80211MessageFactory::CreateMessage(msg));
Wade Guthrie0d438532012-05-18 14:18:50 -0700283 if (message == NULL) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700284 SLOG(WiFi, 3) << __func__ << "(msg:NULL)";
repo syncbcaa6942013-01-02 15:38:21 -0800285 return; // Skip current message, continue parsing buffer.
Christopher Wiley393b93f2012-11-08 17:30:58 -0800286 }
287 // Call (then erase) any message-specific callback.
repo syncbcaa6942013-01-02 15:38:21 -0800288 // TODO(wdg): Support multi-part messages; don't delete callback until last
289 // part appears.
Christopher Wiley393b93f2012-11-08 17:30:58 -0800290 if (ContainsKey(message_callbacks_, sequence_number)) {
291 SLOG(WiFi, 3) << "found message-specific callback";
292 if (message_callbacks_[sequence_number].is_null()) {
293 LOG(ERROR) << "Callback exists but is NULL for ID " << sequence_number;
Wade Guthrie5d3d6de2012-11-02 11:08:34 -0700294 } else {
Christopher Wiley393b93f2012-11-08 17:30:58 -0800295 message_callbacks_[sequence_number].Run(*message);
296 }
297 message_callbacks_.erase(sequence_number);
298 } else {
repo syncbcaa6942013-01-02 15:38:21 -0800299 list<Callback>::const_iterator i = broadcast_callbacks_.begin();
Christopher Wiley393b93f2012-11-08 17:30:58 -0800300 while (i != broadcast_callbacks_.end()) {
repo syncbcaa6942013-01-02 15:38:21 -0800301 SLOG(WiFi, 3) << " " << __func__ << " - calling callback";
302 i->Run(*message);
303 ++i;
Wade Guthrie0d438532012-05-18 14:18:50 -0700304 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700305 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700306}
307
repo syncbcaa6942013-01-02 15:38:21 -0800308void Config80211::OnReadError(const Error &error) {
309 // TODO(wdg): When config80211 is used for scan, et al., this should either be
310 // LOG(FATAL) or the code should properly deal with errors, e.g., dropped
311 // messages due to the socket buffer being full.
312 LOG(ERROR) << "Config80211's netlink Socket read returns error: "
313 << error.message();
314}
315
316
Wade Guthrie0d438532012-05-18 14:18:50 -0700317} // namespace shill.