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
26 using base::Bind;
27 using base::StringPrintf;
28
29 namespace shill {
30
EncodeHeader(uint32_t sequence_number)31 ByteString 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
Encode(uint32_t sequence_number)56 ByteString 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
InitAndStripHeader(NetlinkPacket * packet)75 bool 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
Print(int header_log_level,int detail_log_level) const97 void 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
107 const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;
108
InitFromPacket(NetlinkPacket * packet,NetlinkMessage::MessageContext context)109 bool 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
126 const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
127 const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";
128
129 const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY;
130 const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY";
131
GetFamilyMessage()132 GetFamilyMessage::GetFamilyMessage()
133 : ControlNetlinkMessage(kCommand, kCommandString) {
134 attributes()->CreateStringAttribute(CTRL_ATTR_FAMILY_NAME,
135 "CTRL_ATTR_FAMILY_NAME");
136 }
137
138 // static
CreateMessage(const NetlinkPacket & packet)139 NetlinkMessage* 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