blob: 252bdca45b3707f9ae3c263ac9bceb6cfcdd1c41 [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>
8
9#include <netlink/msg.h>
10
11#include <map>
12#include <sstream>
13#include <string>
14
15#include <base/memory/weak_ptr.h>
Wade Guthried6153612012-08-23 11:36:14 -070016#include <base/stl_util.h>
Wade Guthrie0d438532012-05-18 14:18:50 -070017#include <base/stringprintf.h>
18
19#include "shill/io_handler.h"
20#include "shill/logging.h"
21#include "shill/nl80211_socket.h"
22#include "shill/scope_logger.h"
23#include "shill/user_bound_nlmessage.h"
24
25using base::Bind;
26using base::LazyInstance;
27using base::StringAppendF;
Wade Guthrie0d438532012-05-18 14:18:50 -070028using std::string;
29
30namespace shill {
31
32namespace {
33LazyInstance<Config80211> g_config80211 = LAZY_INSTANCE_INITIALIZER;
Wade Guthrie0d438532012-05-18 14:18:50 -070034} // namespace
35
Wade Guthried6153612012-08-23 11:36:14 -070036Config80211::EventTypeStrings *Config80211::event_types_ = NULL;
Wade Guthrie0d438532012-05-18 14:18:50 -070037
38Config80211::Config80211()
Wade Guthried6153612012-08-23 11:36:14 -070039 : wifi_state_(kWifiDown),
40 dispatcher_(NULL),
Wade Guthrie0d438532012-05-18 14:18:50 -070041 weak_ptr_factory_(this),
42 dispatcher_callback_(Bind(&Config80211::HandleIncomingEvents,
43 weak_ptr_factory_.GetWeakPtr())),
44 sock_(NULL) {
45}
46
47Config80211::~Config80211() {
48 // Since Config80211 is a singleton, it should be safe to delete a static
49 // member.
50 delete event_types_;
51 event_types_ = NULL;
52}
53
54Config80211 *Config80211::GetInstance() {
55 return g_config80211.Pointer();
56}
57
Wade Guthried6153612012-08-23 11:36:14 -070058void Config80211::Reset() {
59 wifi_state_ = kWifiDown;
60 subscribed_events_.clear();
61}
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 }
74 }
75
76 if (!event_types_) {
Wade Guthried6153612012-08-23 11:36:14 -070077 event_types_ = new EventTypeStrings;
Wade Guthrie0d438532012-05-18 14:18:50 -070078 (*event_types_)[Config80211::kEventTypeConfig] = "config";
79 (*event_types_)[Config80211::kEventTypeScan] = "scan";
80 (*event_types_)[Config80211::kEventTypeRegulatory] = "regulatory";
81 (*event_types_)[Config80211::kEventTypeMlme] = "mlme";
82 }
83
84 // Install ourselves in the shill mainloop so we receive messages on the
85 // nl80211 socket.
86 dispatcher_ = dispatcher;
87 if (dispatcher_) {
88 dispatcher_handler_.reset(
89 dispatcher_->CreateReadyHandler(GetFd(),
90 IOHandler::kModeInput,
91 dispatcher_callback_));
92 }
93 return true;
94}
95
96// static
97bool Config80211::GetEventTypeString(EventType type, string *value) {
98 if (!value) {
99 LOG(ERROR) << "NULL |value|";
100 return false;
101 }
102 if (!event_types_) {
103 LOG(ERROR) << "NULL |event_types_|";
104 return false;
105 }
106
Wade Guthried6153612012-08-23 11:36:14 -0700107 EventTypeStrings::iterator match = (*event_types_).find(type);
Wade Guthrie0d438532012-05-18 14:18:50 -0700108 if (match == (*event_types_).end()) {
109 LOG(ERROR) << "Event type " << type << " not found";
110 return false;
111 }
112 *value = match->second;
113 return true;
114}
115
Wade Guthried6153612012-08-23 11:36:14 -0700116void Config80211::SetWifiState(WifiState new_state) {
117 if (wifi_state_ == new_state) {
118 return;
119 }
120
121 // If we're newly-up, subscribe to all the event types that have been
122 // requested.
123 if (new_state == kWifiUp) {
124 SubscribedEvents::const_iterator i;
125 for (i = subscribed_events_.begin(); i != subscribed_events_.end(); ++i) {
Wade Guthried6153612012-08-23 11:36:14 -0700126 ActuallySubscribeToEvents(*i);
127 }
128 }
129 wifi_state_ = new_state;
130}
131
Wade Guthrie0d438532012-05-18 14:18:50 -0700132bool Config80211::SubscribeToEvents(EventType type) {
Wade Guthried6153612012-08-23 11:36:14 -0700133 bool it_worked = true;
134 if (!ContainsKey(subscribed_events_, type)) {
135 if (wifi_state_ == kWifiUp) {
136 it_worked = ActuallySubscribeToEvents(type);
137 }
138 // |subscribed_events_| is a list of events to which we want to subscribe
139 // when wifi comes up (including when it comes _back_ up after it goes
140 // down sometime in the future).
141 subscribed_events_.insert(type);
142 }
143 return it_worked;
144}
145
146bool Config80211::ActuallySubscribeToEvents(EventType type) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700147 string group_name;
148
149 if (!GetEventTypeString(type, &group_name)) {
150 return false;
151 }
152 if (!sock_->AddGroupMembership(group_name)) {
153 return false;
154 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700155 // No sequence checking for multicast messages.
156 if (!sock_->DisableSequenceChecking()) {
157 return false;
158 }
159
160 // Install the global NetLink Callback for messages along with a parameter.
161 // The Netlink Callback's parameter is passed to 'C' as a 'void *'.
162 if (!sock_->SetNetlinkCallback(OnNlMessageReceived,
163 static_cast<void *>(
164 const_cast<Config80211::Callback *>(
165 &default_callback_)))) {
166 return false;
167 }
168 return true;
169}
170
171void Config80211::HandleIncomingEvents(int unused_fd) {
172 sock_->GetMessages();
173}
174
175// NOTE: the "struct nl_msg" declaration, below, is a complete fabrication
176// (but one consistent with the nl_socket_modify_cb call to which
177// |OnNlMessageReceived| is a parameter). |raw_message| is actually a
178// "struct sk_buff" but that data type is only visible in the kernel. We'll
179// scrub this erroneous datatype with the "nlmsg_hdr" call, below, which
180// extracts an nlmsghdr pointer from |raw_message|.
181int Config80211::OnNlMessageReceived(struct nl_msg *raw_message,
182 void *user_callback_object) {
183 SLOG(WiFi, 6) << "\t Entering " << __func__
184 << "( msg:" << raw_message
185 << ", cb:" << user_callback_object << ")";
186
187 string output("@");
188
189 nlmsghdr *msg = nlmsg_hdr(raw_message);
190
191 scoped_ptr<UserBoundNlMessage> message(
192 UserBoundNlMessageFactory::CreateMessage(msg));
193 if (message == NULL) {
194 output.append("unknown event");
195 } else {
196 if (user_callback_object) {
197 Config80211::Callback *bound_object =
198 static_cast<Config80211::Callback *> (user_callback_object);
199 if (!bound_object->is_null()) {
200 bound_object->Run(*message);
201 }
202 }
203 StringAppendF(&output, "%s", message->ToString().c_str());
204 }
205
206 SLOG(WiFi, 5) << output;
207
208 return NL_SKIP; // Skip current message, continue parsing buffer.
209}
210
Wade Guthrie0d438532012-05-18 14:18:50 -0700211} // namespace shill.