blob: 64a7b8462b513d77b6030811460502f9a4ee3bdc [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) {
126 string event_type_string;
127 GetEventTypeString(*i, &event_type_string);
128 ActuallySubscribeToEvents(*i);
129 }
130 }
131 wifi_state_ = new_state;
132}
133
Wade Guthrie0d438532012-05-18 14:18:50 -0700134bool Config80211::SubscribeToEvents(EventType type) {
Wade Guthried6153612012-08-23 11:36:14 -0700135 string event_type_string;
136 GetEventTypeString(type, &event_type_string);
137 bool it_worked = true;
138 if (!ContainsKey(subscribed_events_, type)) {
139 if (wifi_state_ == kWifiUp) {
140 it_worked = ActuallySubscribeToEvents(type);
141 }
142 // |subscribed_events_| is a list of events to which we want to subscribe
143 // when wifi comes up (including when it comes _back_ up after it goes
144 // down sometime in the future).
145 subscribed_events_.insert(type);
146 }
147 return it_worked;
148}
149
150bool Config80211::ActuallySubscribeToEvents(EventType type) {
Wade Guthrie0d438532012-05-18 14:18:50 -0700151 string group_name;
Wade Guthried6153612012-08-23 11:36:14 -0700152 string event_type_string;
153 GetEventTypeString(type, &event_type_string);
Wade Guthrie0d438532012-05-18 14:18:50 -0700154
155 if (!GetEventTypeString(type, &group_name)) {
156 return false;
157 }
158 if (!sock_->AddGroupMembership(group_name)) {
159 return false;
160 }
Wade Guthrie0d438532012-05-18 14:18:50 -0700161 // No sequence checking for multicast messages.
162 if (!sock_->DisableSequenceChecking()) {
163 return false;
164 }
165
166 // Install the global NetLink Callback for messages along with a parameter.
167 // The Netlink Callback's parameter is passed to 'C' as a 'void *'.
168 if (!sock_->SetNetlinkCallback(OnNlMessageReceived,
169 static_cast<void *>(
170 const_cast<Config80211::Callback *>(
171 &default_callback_)))) {
172 return false;
173 }
174 return true;
175}
176
177void Config80211::HandleIncomingEvents(int unused_fd) {
178 sock_->GetMessages();
179}
180
181// NOTE: the "struct nl_msg" declaration, below, is a complete fabrication
182// (but one consistent with the nl_socket_modify_cb call to which
183// |OnNlMessageReceived| is a parameter). |raw_message| is actually a
184// "struct sk_buff" but that data type is only visible in the kernel. We'll
185// scrub this erroneous datatype with the "nlmsg_hdr" call, below, which
186// extracts an nlmsghdr pointer from |raw_message|.
187int Config80211::OnNlMessageReceived(struct nl_msg *raw_message,
188 void *user_callback_object) {
189 SLOG(WiFi, 6) << "\t Entering " << __func__
190 << "( msg:" << raw_message
191 << ", cb:" << user_callback_object << ")";
192
193 string output("@");
194
195 nlmsghdr *msg = nlmsg_hdr(raw_message);
196
197 scoped_ptr<UserBoundNlMessage> message(
198 UserBoundNlMessageFactory::CreateMessage(msg));
199 if (message == NULL) {
200 output.append("unknown event");
201 } else {
202 if (user_callback_object) {
203 Config80211::Callback *bound_object =
204 static_cast<Config80211::Callback *> (user_callback_object);
205 if (!bound_object->is_null()) {
206 bound_object->Run(*message);
207 }
208 }
209 StringAppendF(&output, "%s", message->ToString().c_str());
210 }
211
212 SLOG(WiFi, 5) << output;
213
214 return NL_SKIP; // Skip current message, continue parsing buffer.
215}
216
Wade Guthrie0d438532012-05-18 14:18:50 -0700217} // namespace shill.