Shill: Incorporating the functionality of 'iw event' into shill.
'iw event' has been ported into shill and there are unit tests.
It still needs a facility to send individual messages to the
kernel (and there are comments in the code to show where this is
intended) but this will wait for a later commit.
BUG=None.
TEST=Enclosed unit tests verified against manual test. Ran all WiFi
autotests and output matched 'iw event'.
Change-Id: Ia5f5e8b440d0a657ce7fdb3e2b8b5fc6c95323fe
Reviewed-on: https://gerrit.chromium.org/gerrit/24508
Commit-Ready: Wade Guthrie <wdg@chromium.org>
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
diff --git a/kernel_bound_nlmessage.cc b/kernel_bound_nlmessage.cc
new file mode 100644
index 0000000..9b35ff3
--- /dev/null
+++ b/kernel_bound_nlmessage.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "shill/kernel_bound_nlmessage.h"
+
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+
+#include <base/logging.h>
+
+#include "shill/logging.h"
+#include "shill/netlink_socket.h"
+#include "shill/scope_logger.h"
+
+namespace shill {
+
+const uint32_t KernelBoundNlMessage::kIllegalMessage = 0xFFFFFFFF;
+
+KernelBoundNlMessage::~KernelBoundNlMessage() {
+ if (message_) {
+ nlmsg_free(message_);
+ message_ = NULL;
+ }
+}
+
+bool KernelBoundNlMessage::Init() {
+ message_ = nlmsg_alloc();
+
+ if (!message_) {
+ LOG(ERROR) << "Couldn't allocate |message_|";
+ return false;
+ }
+
+ return true;
+}
+
+uint32_t KernelBoundNlMessage::GetId() const {
+ if (!message_) {
+ LOG(ERROR) << "NULL |message_|";
+ return kIllegalMessage;
+ }
+ struct nlmsghdr *header = nlmsg_hdr(message_);
+ if (!header) {
+ LOG(ERROR) << "Couldn't make header";
+ return kIllegalMessage;
+ }
+ return header->nlmsg_seq;
+}
+
+bool KernelBoundNlMessage::AddNetlinkHeader(uint32_t port, uint32_t seq,
+ int family_id, int hdrlen,
+ int flags, uint8_t cmd,
+ uint8_t version) {
+ if (!message_) {
+ LOG(ERROR) << "NULL |message_|";
+ return false;
+ }
+
+ // Parameters to genlmsg_put:
+ // @message: struct nl_msg *message_.
+ // @pid: netlink pid the message is addressed to.
+ // @seq: sequence number (usually the one of the sender).
+ // @family: generic netlink family.
+ // @flags netlink message flags.
+ // @cmd: netlink command.
+ // @version: version of communication protocol.
+ // genlmsg_put returns a void * pointing to the header but we don't want to
+ // encourage its use outside of this object.
+
+ if (genlmsg_put(message_, port, seq, family_id, hdrlen, flags, cmd, version)
+ == NULL) {
+ LOG(ERROR) << "genlmsg_put returned a NULL pointer.";
+ return false;
+ }
+
+ return true;
+}
+
+int KernelBoundNlMessage::AddAttribute(int attrtype, int attrlen,
+ const void *data) {
+ if (!data) {
+ LOG(ERROR) << "NULL |data| parameter";
+ return -1;
+ }
+ if (!message_) {
+ LOG(ERROR) << "NULL |message_|.";
+ return -1;
+ }
+ return nla_put(message_, attrtype, attrlen, data);
+}
+
+bool KernelBoundNlMessage::Send(NetlinkSocket *socket) {
+ if (!socket) {
+ LOG(ERROR) << "NULL |socket| parameter";
+ return false;
+ }
+ if (!message_) {
+ LOG(ERROR) << "NULL |message_|.";
+ return -1;
+ }
+
+ // Manually set the sequence number -- seems to work.
+ struct nlmsghdr *header = nlmsg_hdr(message_);
+ if (header != 0) {
+ header->nlmsg_seq = socket->GetSequenceNumber();
+ }
+
+ // Complete AND SEND a message.
+ int result = nl_send_auto_complete(
+ const_cast<struct nl_sock *>(socket->GetConstNlSock()), message_);
+
+ SLOG(WiFi, 6) << "NL Message " << GetId() << " ===>";
+
+ if (result < 0) {
+ LOG(ERROR) << "Failed call to 'nl_send_auto_complete': " << result;
+ return false;
+ }
+ return true;
+}
+
+} // namespace shill.