blob: 0028ce16e7aa0ad62a836afc59d02573662aa8ef [file] [log] [blame] [edit]
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net-base/generic_netlink_message.h"
#include <string>
#include <vector>
#include <base/functional/bind.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include "net-base/byte_utils.h"
#include "net-base/netlink_attribute.h"
#include "net-base/netlink_message.h"
#include "net-base/netlink_packet.h"
namespace net_base {
std::vector<uint8_t> GenericNetlinkMessage::EncodeHeader(
uint32_t sequence_number) {
// Build nlmsghdr.
std::vector<uint8_t> result = NetlinkMessage::EncodeHeader(sequence_number);
if (result.size() == 0) {
LOG(ERROR) << "Couldn't encode message header.";
return result;
}
// Build and append the genl message header.
genlmsghdr genl_header;
genl_header.cmd = command();
genl_header.version = 1;
genl_header.reserved = 0;
std::vector<uint8_t> genl_header_bytes = byte_utils::ToBytes(genl_header);
size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
genl_header_bytes.resize(genlmsghdr_with_pad, 0); // Zero-fill.
nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.data());
pheader->nlmsg_len += genlmsghdr_with_pad;
result.insert(result.end(), genl_header_bytes.begin(),
genl_header_bytes.end());
return result;
}
std::vector<uint8_t> GenericNetlinkMessage::Encode(uint32_t sequence_number) {
std::vector<uint8_t> result = EncodeHeader(sequence_number);
if (result.size() == 0) {
LOG(ERROR) << "Couldn't encode message header.";
return result;
}
// Build and append attributes (padding is included by
// AttributeList::Encode).
const std::vector<uint8_t> attribute_bytes = attributes_->Encode();
// Need to re-calculate |header| since |Append|, above, moves the data.
nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.data());
pheader->nlmsg_len += attribute_bytes.size();
result.insert(result.end(), attribute_bytes.begin(), attribute_bytes.end());
return result;
}
bool GenericNetlinkMessage::InitAndStripHeader(NetlinkPacket* packet) {
if (!packet) {
LOG(ERROR) << "NULL packet";
return false;
}
if (!NetlinkMessage::InitAndStripHeader(packet)) {
return false;
}
genlmsghdr gnlh;
if (!packet->ConsumeData(sizeof(gnlh), &gnlh)) {
return false;
}
if (command_ != gnlh.cmd) {
LOG(WARNING) << "This object thinks it's a " << command_
<< " but the message thinks it's a " << gnlh.cmd;
}
return true;
}
std::string GenericNetlinkMessage::ToString() const {
return base::StringPrintf("Message %s (%d)", command_string(), command());
}
void GenericNetlinkMessage::Print(int header_log_level,
int detail_log_level) const {
VLOG(header_log_level) << ToString();
attributes_->Print(detail_log_level, 1);
}
// Control Message
const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;
bool ControlNetlinkMessage::InitFromPacket(NetlinkPacket* packet,
bool is_broadcast) {
if (!packet) {
LOG(ERROR) << "Null |packet| parameter";
return false;
}
if (!InitAndStripHeader(packet)) {
return false;
}
return attributes_->Decode(
packet,
base::BindRepeating(&NetlinkAttribute::NewControlAttributeFromId));
}
// Specific Control types.
const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";
const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY;
const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY";
GetFamilyMessage::GetFamilyMessage()
: ControlNetlinkMessage(kCommand, kCommandString) {
attributes()->CreateStringAttribute(CTRL_ATTR_FAMILY_NAME,
"CTRL_ATTR_FAMILY_NAME");
}
// static
std::unique_ptr<NetlinkMessage> ControlNetlinkMessage::CreateMessage(
const NetlinkPacket& packet) {
genlmsghdr header;
if (!packet.GetGenlMsgHdr(&header)) {
LOG(ERROR) << "Could not read genl header.";
return nullptr;
}
switch (header.cmd) {
case NewFamilyMessage::kCommand:
return std::make_unique<NewFamilyMessage>();
case GetFamilyMessage::kCommand:
return std::make_unique<GetFamilyMessage>();
default:
LOG(WARNING) << "Unknown/unhandled netlink control message "
<< header.cmd;
return std::make_unique<UnknownControlMessage>(header.cmd);
}
}
} // namespace net_base