blob: 4e8adc754a0359df7e86c997a7b690b8e56c8b63 [file] [log] [blame]
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -07001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/generic_netlink_message.h"
6
7#include <netlink/msg.h>
8#include <netlink/netlink.h>
9
10#include <base/bind.h>
11#include <base/stringprintf.h>
12
13#include "shill/logging.h"
14#include "shill/netlink_attribute.h"
15
16using base::Bind;
17using base::StringPrintf;
18
19namespace shill {
20
21ByteString GenericNetlinkMessage::EncodeHeader(uint32_t sequence_number) {
22 // Build nlmsghdr.
23 ByteString result(NetlinkMessage::EncodeHeader(sequence_number));
24 if (result.GetLength() == 0) {
25 LOG(ERROR) << "Couldn't encode message header.";
26 return result;
27 }
28
29 // Build and append the genl message header.
30 genlmsghdr genl_header;
31 genl_header.cmd = command();
32 genl_header.version = 1;
33 genl_header.reserved = 0;
34
35 ByteString genl_header_string(
36 reinterpret_cast<unsigned char *>(&genl_header), sizeof(genl_header));
37 size_t genlmsghdr_with_pad = NLMSG_ALIGN(sizeof(genl_header));
38 genl_header_string.Resize(genlmsghdr_with_pad); // Zero-fill.
39
40 nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
41 pheader->nlmsg_len += genlmsghdr_with_pad;
42 result.Append(genl_header_string);
43 return result;
44}
45
46ByteString GenericNetlinkMessage::Encode(uint32_t sequence_number) {
47 ByteString result(EncodeHeader(sequence_number));
48 if (result.GetLength() == 0) {
49 LOG(ERROR) << "Couldn't encode message header.";
50 return result;
51 }
52
53 // Build and append attributes (padding is included by
54 // AttributeList::Encode).
55 ByteString attribute_string = attributes_->Encode();
56
57 // Need to re-calculate |header| since |Append|, above, moves the data.
58 nlmsghdr *pheader = reinterpret_cast<nlmsghdr *>(result.GetData());
59 pheader->nlmsg_len += attribute_string.GetLength();
60 result.Append(attribute_string);
61
62 return result;
63}
64
65bool GenericNetlinkMessage::InitAndStripHeader(ByteString *input) {
66 if (!input) {
67 LOG(ERROR) << "NULL input";
68 return false;
69 }
70 if (!NetlinkMessage::InitAndStripHeader(input)) {
71 return false;
72 }
73
74 // Read the genlmsghdr.
75 genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(input->GetData());
76 if (command_ != gnlh->cmd) {
77 LOG(WARNING) << "This object thinks it's a " << command_
78 << " but the message thinks it's a " << gnlh->cmd;
79 }
80
81 // Strip the genlmsghdr.
82 input->RemovePrefix(NLMSG_ALIGN(sizeof(struct genlmsghdr)));
83 return true;
84}
85
Wade Guthrie0b1ebf12013-04-12 09:53:33 -070086void GenericNetlinkMessage::Print(int header_log_level,
87 int detail_log_level) const {
88 SLOG(WiFi, header_log_level) << StringPrintf("Message %s (%d)",
89 command_string(),
90 command());
91 attributes_->Print(detail_log_level, 1);
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -070092}
93
94// Control Message
95
96const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL;
97
98bool ControlNetlinkMessage::InitFromNlmsg(const nlmsghdr *const_msg) {
99 if (!const_msg) {
100 LOG(ERROR) << "Null |msg| parameter";
101 return false;
102 }
103 ByteString message(reinterpret_cast<const unsigned char *>(const_msg),
104 const_msg->nlmsg_len);
105
106 if (!InitAndStripHeader(&message)) {
107 return false;
108 }
109
110 // Attributes.
111 // Parse the attributes from the nl message payload into the 'tb' array.
112 nlattr *tb[CTRL_ATTR_MAX + 1];
113 nla_parse(tb, CTRL_ATTR_MAX,
114 reinterpret_cast<nlattr *>(message.GetData()), message.GetLength(),
115 NULL);
116
117 for (int i = 0; i < CTRL_ATTR_MAX + 1; ++i) {
118 if (tb[i]) {
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -0700119 attributes_->CreateAndInitAttribute(
120 i, tb[i], Bind(&NetlinkAttribute::NewControlAttributeFromId));
121 }
122 }
123 return true;
124}
125
126// Specific Control types.
127
128const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
129const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";
130
131const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY;
132const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY";
133
Wade Guthrie2623f1a2013-05-14 15:14:54 -0700134GetFamilyMessage::GetFamilyMessage()
135 : ControlNetlinkMessage(kCommand, kCommandString) {
136 attributes()->CreateStringAttribute(CTRL_ATTR_FAMILY_NAME,
137 "CTRL_ATTR_FAMILY_NAME");
138}
139
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -0700140// static
141NetlinkMessage *ControlNetlinkMessage::CreateMessage(
142 const nlmsghdr *const_msg) {
143 if (!const_msg) {
144 LOG(ERROR) << "NULL |const_msg| parameter";
145 return NULL;
146 }
147 // Casting away constness since, while nlmsg_data doesn't change its
148 // parameter, it also doesn't declare its paramenter as const.
149 nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
150 void *payload = nlmsg_data(msg);
151 genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
152
153 switch (gnlh->cmd) {
154 case NewFamilyMessage::kCommand:
155 return new NewFamilyMessage();
156 case GetFamilyMessage::kCommand:
157 return new GetFamilyMessage();
158 default:
159 LOG(WARNING) << "Unknown/unhandled netlink control message " << gnlh->cmd;
Wade Guthrie40d992c2013-04-19 11:10:11 -0700160 return new UnknownControlMessage(gnlh->cmd);
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -0700161 break;
162 }
163 return NULL;
164}
165
166} // namespace shill.