blob: 3e0d04dc56dbe21c0df7be2c7512fb603c5ccc0e [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 Guthriebb9fca22013-04-10 17:21:42 -0700119 // TODO(wdg): When NetlinkMessages instantiate their own attributes,
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -0700120 // this call should, instead, call |SetAttributeFromNlAttr|.
121 attributes_->CreateAndInitAttribute(
122 i, tb[i], Bind(&NetlinkAttribute::NewControlAttributeFromId));
123 }
124 }
125 return true;
126}
127
128// Specific Control types.
129
130const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY;
131const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY";
132
133const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY;
134const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY";
135
136// static
137NetlinkMessage *ControlNetlinkMessage::CreateMessage(
138 const nlmsghdr *const_msg) {
139 if (!const_msg) {
140 LOG(ERROR) << "NULL |const_msg| parameter";
141 return NULL;
142 }
143 // Casting away constness since, while nlmsg_data doesn't change its
144 // parameter, it also doesn't declare its paramenter as const.
145 nlmsghdr *msg = const_cast<nlmsghdr *>(const_msg);
146 void *payload = nlmsg_data(msg);
147 genlmsghdr *gnlh = reinterpret_cast<genlmsghdr *>(payload);
148
149 switch (gnlh->cmd) {
150 case NewFamilyMessage::kCommand:
151 return new NewFamilyMessage();
152 case GetFamilyMessage::kCommand:
153 return new GetFamilyMessage();
154 default:
155 LOG(WARNING) << "Unknown/unhandled netlink control message " << gnlh->cmd;
Wade Guthrie40d992c2013-04-19 11:10:11 -0700156 return new UnknownControlMessage(gnlh->cmd);
Wade Guthrie0ae4b8e2013-04-10 16:49:15 -0700157 break;
158 }
159 return NULL;
160}
161
162} // namespace shill.