shill: Add message-specific callbacks to the nl80211 code.
This allows users to create a one-off nl80211 message, install a
callback for that message, and then send the message to the kernel.
When the response is issued, the callback will be called and then
removed from the system.
BUG=chromium-os:35129
TEST=Manual and unit tests (including new ones).
Change-Id: I06bf8d16629f3eac226209b49827289e7a9cdca3
Reviewed-on: https://gerrit.chromium.org/gerrit/36904
Reviewed-by: Christopher Wiley <wiley@chromium.org>
Commit-Ready: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/config80211.cc b/config80211.cc
index 4dc9975..fa47642 100644
--- a/config80211.cc
+++ b/config80211.cc
@@ -136,6 +136,38 @@
broadcast_callbacks_.clear();
}
+bool Config80211::SetMessageCallback(const KernelBoundNlMessage &message,
+ const Callback &callback) {
+ LOG(INFO) << "Setting callback for message " << message.GetId();
+ uint32_t message_id = message.GetId();
+ if (message_id == 0) {
+ LOG(ERROR) << "Message ID 0 is reserved for broadcast callbacks.";
+ return false;
+ }
+
+ if (ContainsKey(message_callbacks_, message_id)) {
+ LOG(ERROR) << "Already a callback assigned for id " << message_id;
+ return false;
+ }
+
+ if (callback.is_null()) {
+ LOG(ERROR) << "Trying to add a NULL callback for id " << message_id;
+ return false;
+ }
+
+ message_callbacks_[message_id] = callback;
+ return true;
+}
+
+bool Config80211::UnsetMessageCallbackById(uint32_t message_id) {
+ if (!ContainsKey(message_callbacks_, message_id)) {
+ LOG(WARNING) << "No callback assigned for id " << message_id;
+ return false;
+ }
+ message_callbacks_.erase(message_id);
+ return true;
+}
+
// static
bool Config80211::GetEventTypeString(EventType type, string *value) {
if (!value) {
@@ -243,20 +275,29 @@
SLOG(WiFi, 3) << __func__ << "(msg:NULL)";
} else {
SLOG(WiFi, 3) << __func__ << "(msg:" << msg->nlmsg_seq << ")";
- list<Callback>::iterator i = broadcast_callbacks_.begin();
- while (i != broadcast_callbacks_.end()) {
- SLOG(WiFi, 3) << " " << __func__ << " - found callback";
- if (i->is_null()) {
- // How did this get in here?
- LOG(WARNING) << "Removing NULL callback from list";
- list<Callback>::iterator temp = i;
- ++temp;
- broadcast_callbacks_.erase(i);
- i = temp;
+ // Call (then erase) any message-specific callback.
+ if (ContainsKey(message_callbacks_, message->GetId())) {
+ SLOG(WiFi, 3) << "found message-specific callback";
+ if (message_callbacks_[message->GetId()].is_null()) {
+ LOG(ERROR) << "Callback exists but is NULL for ID " << message->GetId();
} else {
- SLOG(WiFi, 3) << " " << __func__ << " - calling callback";
- i->Run(*message);
- ++i;
+ message_callbacks_[message->GetId()].Run(*message);
+ }
+ UnsetMessageCallbackById(message->GetId());
+ } else {
+ list<Callback>::iterator i = broadcast_callbacks_.begin();
+ while (i != broadcast_callbacks_.end()) {
+ SLOG(WiFi, 3) << "found a broadcast callback";
+ if (i->is_null()) {
+ list<Callback>::iterator temp = i;
+ ++temp;
+ broadcast_callbacks_.erase(i);
+ i = temp;
+ } else {
+ SLOG(WiFi, 3) << " " << __func__ << " - calling callback";
+ i->Run(*message);
+ ++i;
+ }
}
}
}