161 lines
4.7 KiB
C++
161 lines
4.7 KiB
C++
//
|
|
// Copyright (C) 2013 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#include "shill/net/generic_netlink_message.h"
|
|
|
|
#include <base/bind.h>
|
|
#include <base/logging.h>
|
|
#include <base/strings/stringprintf.h>
|
|
|
|
#include "shill/net/netlink_attribute.h"
|
|
#include "shill/net/netlink_packet.h"
|
|
|
|
using base::Bind;
|
|
using base::StringPrintf;
|
|
|
|
namespace shill {
|
|
|
|
ByteString GenericNetlinkMessage::EncodeHeader(uint32_t sequence_number) {
|
|
// Build nlmsghdr.
|
|
ByteString result(NetlinkMessage::EncodeHeader(sequence_number));
|
|
if (result.GetLength() == 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;
|
|
|
|
ByteString genl_header_string(
|
|
reinterpret_cast<unsigned char*>(&genl_header), sizeof(genl_header));
|
|
size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
|
|
genl_header_string.Resize(genlmsghdr_with_pad); // Zero-fill.
|
|
|
|
nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.GetData());
|
|
pheader->nlmsg_len += genlmsghdr_with_pad;
|
|
result.Append(genl_header_string);
|
|
return result;
|
|
}
|
|
|
|
ByteString GenericNetlinkMessage::Encode(uint32_t sequence_number) {
|
|
ByteString result(EncodeHeader(sequence_number));
|
|
if (result.GetLength() == 0) {
|
|
LOG(ERROR) << "Couldn't encode message header.";
|
|
return result;
|
|
}
|
|
|
|
// Build and append attributes (padding is included by
|
|
// AttributeList::Encode).
|
|
ByteString attribute_string = attributes_->Encode();
|
|
|
|
// Need to re-calculate |header| since |Append|, above, moves the data.
|
|
nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.GetData());
|
|
pheader->nlmsg_len += attribute_string.GetLength();
|
|
result.Append(attribute_string);
|
|
|
|
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;
|
|
}
|
|
|
|
void GenericNetlinkMessage::Print(int header_log_level,
|
|
int detail_log_level) const {
|
|
VLOG(header_log_level) << StringPrintf("Message %s (%d)",
|
|
command_string(),
|
|
command());
|
|
attributes_->Print(detail_log_level, 1);
|
|
}
|
|
|
|
// Control Message
|
|
|
|
const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;
|
|
|
|
bool ControlNetlinkMessage::InitFromPacket(
|
|
NetlinkPacket* packet, NetlinkMessage::MessageContext context) {
|
|
if (!packet) {
|
|
LOG(ERROR) << "Null |packet| parameter";
|
|
return false;
|
|
}
|
|
|
|
if (!InitAndStripHeader(packet)) {
|
|
return false;
|
|
}
|
|
|
|
return packet->ConsumeAttributes(
|
|
Bind(&NetlinkAttribute::NewControlAttributeFromId), attributes_);
|
|
}
|
|
|
|
// 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
|
|
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 new NewFamilyMessage();
|
|
case GetFamilyMessage::kCommand:
|
|
return new GetFamilyMessage();
|
|
default:
|
|
LOG(WARNING) << "Unknown/unhandled netlink control message "
|
|
<< header.cmd;
|
|
return new UnknownControlMessage(header.cmd);
|
|
break;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace shill.
|