blob: 9b35ff37297e03d18f3ab485835b3da60aaf3faa [file] [log] [blame]
// 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.