Wade Guthrie | 0ae4b8e | 2013-04-10 16:49:15 -0700 | [diff] [blame] | 1 | // 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 | |
| 16 | using base::Bind; |
| 17 | using base::StringPrintf; |
| 18 | |
| 19 | namespace shill { |
| 20 | |
| 21 | ByteString 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 | |
| 46 | ByteString 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 | |
| 65 | bool 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 Guthrie | 0b1ebf1 | 2013-04-12 09:53:33 -0700 | [diff] [blame] | 86 | void 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 Guthrie | 0ae4b8e | 2013-04-10 16:49:15 -0700 | [diff] [blame] | 92 | } |
| 93 | |
| 94 | // Control Message |
| 95 | |
| 96 | const uint16_t ControlNetlinkMessage::kMessageType = GENL_ID_CTRL; |
| 97 | |
| 98 | bool 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 Guthrie | 0ae4b8e | 2013-04-10 16:49:15 -0700 | [diff] [blame] | 119 | attributes_->CreateAndInitAttribute( |
| 120 | i, tb[i], Bind(&NetlinkAttribute::NewControlAttributeFromId)); |
| 121 | } |
| 122 | } |
| 123 | return true; |
| 124 | } |
| 125 | |
| 126 | // Specific Control types. |
| 127 | |
| 128 | const uint8_t NewFamilyMessage::kCommand = CTRL_CMD_NEWFAMILY; |
| 129 | const char NewFamilyMessage::kCommandString[] = "CTRL_CMD_NEWFAMILY"; |
| 130 | |
| 131 | const uint8_t GetFamilyMessage::kCommand = CTRL_CMD_GETFAMILY; |
| 132 | const char GetFamilyMessage::kCommandString[] = "CTRL_CMD_GETFAMILY"; |
| 133 | |
Wade Guthrie | 2623f1a | 2013-05-14 15:14:54 -0700 | [diff] [blame] | 134 | GetFamilyMessage::GetFamilyMessage() |
| 135 | : ControlNetlinkMessage(kCommand, kCommandString) { |
| 136 | attributes()->CreateStringAttribute(CTRL_ATTR_FAMILY_NAME, |
| 137 | "CTRL_ATTR_FAMILY_NAME"); |
| 138 | } |
| 139 | |
Wade Guthrie | 0ae4b8e | 2013-04-10 16:49:15 -0700 | [diff] [blame] | 140 | // static |
| 141 | NetlinkMessage *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 Guthrie | 40d992c | 2013-04-19 11:10:11 -0700 | [diff] [blame] | 160 | return new UnknownControlMessage(gnlh->cmd); |
Wade Guthrie | 0ae4b8e | 2013-04-10 16:49:15 -0700 | [diff] [blame] | 161 | break; |
| 162 | } |
| 163 | return NULL; |
| 164 | } |
| 165 | |
| 166 | } // namespace shill. |