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