// // 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.