blob: 4dc99750bd6696891e3c1e424b8fd735d33c3faa [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"
18#include "shill/logging.h"
19#include "shill/nl80211_socket.h"
20#include "shill/scope_logger.h"
21#include "shill/user_bound_nlmessage.h"
22
23using base::Bind;
24using base::LazyInstance;
Wade Guthrieb1ec8602012-10-18 17:26:14 -070025using std::list;
Wade Guthrie0d438532012-05-18 14:18:50 -070026using std::string;
27
28namespace shill {
29
30namespace {
31LazyInstance<Config80211> g_config80211 = LAZY_INSTANCE_INITIALIZER;
Wade Guthrie0d438532012-05-18 14:18:50 -070032} // namespace
33
Wade Guthried6153612012-08-23 11:36:14 -070034Config80211::EventTypeStrings *Config80211::event_types_ = NULL;
Wade Guthrie0d438532012-05-18 14:18:50 -070035
36Config80211::Config80211()
Wade Guthried6153612012-08-23 11:36:14 -070037 : wifi_state_(kWifiDown),
38 dispatcher_(NULL),
Wade Guthrie0d438532012-05-18 14:18:50 -070039 weak_ptr_factory_(this),
40 dispatcher_callback_(Bind(&Config80211::HandleIncomingEvents,
41 weak_ptr_factory_.GetWeakPtr())),
42 sock_(NULL) {
43}
44
45Config80211::~Config80211() {
46 // Since Config80211 is a singleton, it should be safe to delete a static
47 // member.
48 delete event_types_;
49 event_types_ = NULL;
50}
51
52Config80211 *Config80211::GetInstance() {
53 return g_config80211.Pointer();
54}
55
Wade Guthried6153612012-08-23 11:36:14 -070056void Config80211::Reset() {
57 wifi_state_ = kWifiDown;
58 subscribed_events_.clear();
Wade Guthrieb1ec8602012-10-18 17:26:14 -070059 ClearBroadcastCallbacks();
Wade Guthried6153612012-08-23 11:36:14 -070060}
61
Wade Guthrie0d438532012-05-18 14:18:50 -070062bool Config80211::Init(EventDispatcher *dispatcher) {
63 if (!sock_) {
64 sock_ = new Nl80211Socket;
65 if (!sock_) {
66 LOG(ERROR) << "No memory";
67 return false;
68 }
69
70 if (!sock_->Init()) {
71 return false;
72 }
73 }
74
75 if (!event_types_) {
Wade Guthried6153612012-08-23 11:36:14 -070076 event_types_ = new EventTypeStrings;
Wade Guthrie0d438532012-05-18 14:18:50 -070077 (*event_types_)[Config80211::kEventTypeConfig] = "config";
78 (*event_types_)[Config80211::kEventTypeScan] = "scan";
79 (*event_types_)[Config80211::kEventTypeRegulatory] = "regulatory";
80 (*event_types_)[Config80211::kEventTypeMlme] = "mlme";
81 }
82
83 // Install ourselves in the shill mainloop so we receive messages on the
84 // nl80211 socket.
85 dispatcher_ = dispatcher;
86 if (dispatcher_) {
87 dispatcher_handler_.reset(
88 dispatcher_->CreateReadyHandler(GetFd(),
89 IOHandler::kModeInput,
90 dispatcher_callback_));
91 }
92 return true;
93}
94
Wade Guthrieb1ec8602012-10-18 17:26:14 -070095bool Config80211::AddBroadcastCallback(const Callback &callback) {
96 list<Callback>::iterator i;
97 if (FindBroadcastCallback(callback)) {
98 LOG(WARNING) << "Trying to re-add a callback";
99 return false; // Should only be one copy in the list.
100 }
101 if (callback.is_null()) {
102 LOG(WARNING) << "Trying to add a NULL callback";
103 return false;
104 }
105 // And add the callback to the list.
106 SLOG(WiFi, 3) << "Config80211::" << __func__ << " - adding callback";
107 broadcast_callbacks_.push_back(callback);
108 return true;
109}
110
111bool Config80211::RemoveBroadcastCallback(const Callback &callback) {
112 list<Callback>::iterator i;
113 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
114 if ((*i).Equals(callback)) {
115 broadcast_callbacks_.erase(i);
116 // Should only be one copy in the list so we don't have to continue
117 // looking for another one.
118 return true;
119 }
120 }
121 LOG(WARNING) << "Callback not found.";
122 return false;
123}
124
125bool Config80211::FindBroadcastCallback(const Callback &callback) const {
126 list<Callback>::const_iterator i;
127 for (i = broadcast_callbacks_.begin(); i != broadcast_callbacks_.end(); ++i) {
128 if ((*i).Equals(callback)) {
129 return true;
130 }
131 }
132 return false;
133}
134
135void Config80211::ClearBroadcastCallbacks() {
136 broadcast_callbacks_.clear();
137}
138
Wade Guthrie0d438532012-05-18 14:18:50 -0700139// static
140bool Config80211::GetEventTypeString(EventType type, string *value) {
141 if (!value) {
142 LOG(ERROR) << "NULL |value|";
143 return false;
144 }
145 if (!event_types_) {
146 LOG(ERROR) << "NULL |event_types_|";
147 return false;
148 }
149
Wade Guthried6153612012-08-23 11:36:14 -0700150 EventTypeStrings::iterator match = (*event_types_).find(type);
Wade Guthrie0d438532012-05-18 14:18:50 -0700151 if (match == (*event_types_).end()) {
152 LOG(ERROR) << "Event type " << type << " not found";
153 return false;
154 }
155 *value = match->second;
156 return true;
157}
158
Wade Guthried6153612012-08-23 11:36:14 -0700159void Config80211::SetWifiState(WifiState new_state) {
160 if (wifi_state_ == new_state) {
161 return;
162 }
163
164 // If we're newly-up, subscribe to all the event types that have been
165 // requested.
166 if (new_state == kWifiUp) {
167 SubscribedEvents::const_iterator i;
168 for (i = subscribed_events_.begin(); i != subscribed_events_.end(); ++i) {
Wade Guthried6153612012-08-23 11:36:14 -0700169 ActuallySubscribeToEvents(*i);
170 }
171 }
172 wifi_state_ = new_state;
173}
174
Wade Guthrie0d438532012-05-18 14:18:50 -0700175bool Config80211::SubscribeToEvents(EventType type) {
Wade Guthried6153612012-08-23 11:36:14 -0700176 bool it_worked = true;
177 if (!ContainsKey(subscribed_events_, type)) {
178 if (wifi_state_ == kWifiUp) {
179 it_worked = ActuallySubscribeToEvents(type);
180 }
181 // |subscribed_events_| is a list of events to which we want to subscribe
182 // when wifi comes up (including when it comes _back_ up after it goes
183 // down sometime in the future).
184 subscribed_events_.insert(type);
185 }
186 return it_worked;
187}
188
189bool Config80211::ActuallySubscribeToEvents(EventType type) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700190 string group_name;
191
192 if (!GetEventTypeString(type, &group_name)) {
193 return false;
194 }
195 if (!sock_->AddGroupMembership(group_name)) {
196 return false;
197 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700198 // No sequence checking for multicast messages.
199 if (!sock_->DisableSequenceChecking()) {
200 return false;
201 }
202
203 // Install the global NetLink Callback for messages along with a parameter.
204 // The Netlink Callback's parameter is passed to 'C' as a 'void *'.
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700205 if (!sock_->SetNetlinkCallback(OnRawNlMessageReceived,
206 static_cast<void *>(this))) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700207 return false;
208 }
209 return true;
210}
211
212void Config80211::HandleIncomingEvents(int unused_fd) {
213 sock_->GetMessages();
214}
215
216// NOTE: the "struct nl_msg" declaration, below, is a complete fabrication
217// (but one consistent with the nl_socket_modify_cb call to which
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700218// |OnRawNlMessageReceived| is a parameter). |raw_message| is actually a
Wade Guthrie0d438532012-05-18 14:18:50 -0700219// "struct sk_buff" but that data type is only visible in the kernel. We'll
220// scrub this erroneous datatype with the "nlmsg_hdr" call, below, which
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700221// extracts an nlmsghdr pointer from |raw_message|. We'll, then, pass this to
222// a separate method, |OnNlMessageReceived|, to make testing easier.
Wade Guthrie0d438532012-05-18 14:18:50 -0700223
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700224// static
225int Config80211::OnRawNlMessageReceived(struct nl_msg *raw_message,
226 void *void_config80211) {
227 if (!void_config80211) {
228 LOG(WARNING) << "NULL config80211 parameter";
229 return NL_SKIP; // Skip current message, continue parsing buffer.
230 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700231
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700232 Config80211 *config80211 = static_cast<Config80211 *>(void_config80211);
233 SLOG(WiFi, 3) << " " << __func__ << " calling OnNlMessageReceived";
234 return config80211->OnNlMessageReceived(nlmsg_hdr(raw_message));
235}
Wade Guthrie0d438532012-05-18 14:18:50 -0700236
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700237int Config80211::OnNlMessageReceived(nlmsghdr *msg) {
238 SLOG(WiFi, 3) << "\t Entering " << __func__
239 << "( msg:" << msg->nlmsg_seq << ")";
Wade Guthrie0d438532012-05-18 14:18:50 -0700240 scoped_ptr<UserBoundNlMessage> message(
241 UserBoundNlMessageFactory::CreateMessage(msg));
242 if (message == NULL) {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700243 SLOG(WiFi, 3) << __func__ << "(msg:NULL)";
Wade Guthrie0d438532012-05-18 14:18:50 -0700244 } else {
Wade Guthrieb1ec8602012-10-18 17:26:14 -0700245 SLOG(WiFi, 3) << __func__ << "(msg:" << msg->nlmsg_seq << ")";
246 list<Callback>::iterator i = broadcast_callbacks_.begin();
247 while (i != broadcast_callbacks_.end()) {
248 SLOG(WiFi, 3) << " " << __func__ << " - found callback";
249 if (i->is_null()) {
250 // How did this get in here?
251 LOG(WARNING) << "Removing NULL callback from list";
252 list<Callback>::iterator temp = i;
253 ++temp;
254 broadcast_callbacks_.erase(i);
255 i = temp;
256 } else {
257 SLOG(WiFi, 3) << " " << __func__ << " - calling callback";
258 i->Run(*message);
259 ++i;
Wade Guthrie0d438532012-05-18 14:18:50 -0700260 }
261 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700262 }
263
Wade Guthrie0d438532012-05-18 14:18:50 -0700264 return NL_SKIP; // Skip current message, continue parsing buffer.
265}
266
Wade Guthrie0d438532012-05-18 14:18:50 -0700267} // namespace shill.