1// 2// Copyright (C) 2013 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "shill/net/generic_netlink_message.h" 18 19#include <base/bind.h> 20#include <base/logging.h> 21#include <base/strings/stringprintf.h> 22 23#include "shill/net/netlink_attribute.h" 24#include "shill/net/netlink_packet.h" 25 26using base::Bind; 27using base::StringPrintf; 28 29namespace shill { 30 31ByteString GenericNetlinkMessage::EncodeHeader(uint32_t sequence_number) { 32 // Build nlmsghdr. 33 ByteString result(NetlinkMessage::EncodeHeader(sequence_number)); 34 if (result.GetLength() == 0) { 35 LOG(ERROR) << "Couldn't encode message header."; 36 return result; 37 } 38 39 // Build and append the genl message header. 40 genlmsghdr genl_header; 41 genl_header.cmd = command(); 42 genl_header.version = 1; 43 genl_header.reserved = 0; 44 45 ByteString genl_header_string( 46 reinterpret_cast<unsigned char*>(&genl_header), sizeof(genl_header)); 47 size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header)); 48 genl_header_string.Resize(genlmsghdr_with_pad); // Zero-fill. 49 50 nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.GetData()); 51 pheader->nlmsg_len += genlmsghdr_with_pad; 52 result.Append(genl_header_string); 53 return result; 54} 55 56ByteString GenericNetlinkMessage::Encode(uint32_t sequence_number) { 57 ByteString result(EncodeHeader(sequence_number)); 58 if (result.GetLength() == 0) { 59 LOG(ERROR) << "Couldn't encode message header."; 60 return result; 61 } 62 63 // Build and append attributes (padding is included by 64 // AttributeList::Encode). 65 ByteString attribute_string = attributes_->Encode(); 66 67 // Need to re-calculate |header| since |Append|, above, moves the data. 68 nlmsghdr* pheader = reinterpret_cast<nlmsghdr*>(result.GetData()); 69 pheader->nlmsg_len += attribute_string.GetLength(); 70 result.Append(attribute_string); 71 72 return result; 73} 74 75bool GenericNetlinkMessage::InitAndStripHeader(NetlinkPacket* packet) { 76 if (!packet) { 77 LOG(ERROR) << "NULL packet"; 78 return false; 79 } 80 if (!NetlinkMessage::InitAndStripHeader(packet)) { 81 return false; 82 } 83 84 genlmsghdr gnlh; 85 if (!packet->ConsumeData(sizeof(gnlh), &gnlh)) { 86 return false; 87 } 88 89 if (command_ != gnlh.cmd) { 90 LOG(WARNING) << "This object thinks it's a " << command_ 91 << " but the message thinks it's a " << gnlh.cmd; 92 } 93 94 return true; 95} 96 97void GenericNetlinkMessage::Print(int header_log_level, 98 int detail_log_level) const { 99 VLOG(header_log_level) << StringPrintf("Message %s (%d)", 100 command_string(), 101 command()); 102 attributes_->Print(detail_log_level, 1); 103} 104 105// Control Message 106 107const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL; 108 109bool ControlNetlinkMessage::InitFromPacket( 110 NetlinkPacket* packet, NetlinkMessage::MessageContext context) { 111 if (!packet) { 112 LOG(ERROR) << "Null |packet| parameter"; 113 return false; 114 } 115 116 if (!InitAndStripHeader(packet)) { 117 return false; 118 } 119 120 return packet->ConsumeAttributes( 121 Bind(&NetlinkAttribute::NewControlAttributeFromId), attributes_); 122} 123 124// Specific Control types. 125 126const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY; 127const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY"; 128 129const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY; 130const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY"; 131 132GetFamilyMessage::GetFamilyMessage() 133 : ControlNetlinkMessage(kCommand, kCommandString) { 134 attributes()->CreateStringAttribute(CTRL_ATTR_FAMILY_NAME, 135 "CTRL_ATTR_FAMILY_NAME"); 136} 137 138// static 139NetlinkMessage* ControlNetlinkMessage::CreateMessage( 140 const NetlinkPacket& packet) { 141 genlmsghdr header; 142 if (!packet.GetGenlMsgHdr(&header)) { 143 LOG(ERROR) << "Could not read genl header."; 144 return nullptr; 145 } 146 147 switch (header.cmd) { 148 case NewFamilyMessage::kCommand: 149 return new NewFamilyMessage(); 150 case GetFamilyMessage::kCommand: 151 return new GetFamilyMessage(); 152 default: 153 LOG(WARNING) << "Unknown/unhandled netlink control message " 154 << header.cmd; 155 return new UnknownControlMessage(header.cmd); 156 break; 157 } 158 return nullptr; 159} 160 161} // namespace shill. 162