| // Copyright (c) 2019 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "quiche/quic/qbone/platform/rtnetlink_message.h" | 
 |  | 
 | #include <memory> | 
 | #include <utility> | 
 |  | 
 | namespace quic { | 
 |  | 
 | RtnetlinkMessage::RtnetlinkMessage(uint16_t type, uint16_t flags, uint32_t seq, | 
 |                                    uint32_t pid, const void* payload_header, | 
 |                                    size_t payload_header_length) { | 
 |   auto* buf = new uint8_t[NLMSG_SPACE(payload_header_length)]; | 
 |   memset(buf, 0, NLMSG_SPACE(payload_header_length)); | 
 |  | 
 |   auto* message_header = reinterpret_cast<struct nlmsghdr*>(buf); | 
 |   message_header->nlmsg_len = NLMSG_LENGTH(payload_header_length); | 
 |   message_header->nlmsg_type = type; | 
 |   message_header->nlmsg_flags = flags; | 
 |   message_header->nlmsg_seq = seq; | 
 |   message_header->nlmsg_pid = pid; | 
 |  | 
 |   if (payload_header != nullptr) { | 
 |     memcpy(NLMSG_DATA(message_header), payload_header, payload_header_length); | 
 |   } | 
 |   message_.push_back({buf, NLMSG_SPACE(payload_header_length)}); | 
 | } | 
 |  | 
 | RtnetlinkMessage::~RtnetlinkMessage() { | 
 |   for (const auto& iov : message_) { | 
 |     delete[] reinterpret_cast<uint8_t*>(iov.iov_base); | 
 |   } | 
 | } | 
 |  | 
 | void RtnetlinkMessage::AppendAttribute(uint16_t type, const void* data, | 
 |                                        uint16_t data_length) { | 
 |   auto* buf = new uint8_t[RTA_SPACE(data_length)]; | 
 |   memset(buf, 0, RTA_SPACE(data_length)); | 
 |  | 
 |   auto* rta = reinterpret_cast<struct rtattr*>(buf); | 
 |   static_assert(sizeof(uint16_t) == sizeof(rta->rta_len), | 
 |                 "struct rtattr uses unsigned short, it's no longer 16bits"); | 
 |   static_assert(sizeof(uint16_t) == sizeof(rta->rta_type), | 
 |                 "struct rtattr uses unsigned short, it's no longer 16bits"); | 
 |  | 
 |   rta->rta_len = RTA_LENGTH(data_length); | 
 |   rta->rta_type = type; | 
 |   memcpy(RTA_DATA(rta), data, data_length); | 
 |  | 
 |   message_.push_back({buf, RTA_SPACE(data_length)}); | 
 |   AdjustMessageLength(rta->rta_len); | 
 | } | 
 |  | 
 | std::unique_ptr<struct iovec[]> RtnetlinkMessage::BuildIoVec() const { | 
 |   auto message = std::make_unique<struct iovec[]>(message_.size()); | 
 |   int idx = 0; | 
 |   for (const auto& vec : message_) { | 
 |     message[idx++] = vec; | 
 |   } | 
 |   return message; | 
 | } | 
 |  | 
 | size_t RtnetlinkMessage::IoVecSize() const { return message_.size(); } | 
 |  | 
 | void RtnetlinkMessage::AdjustMessageLength(size_t additional_data_length) { | 
 |   MessageHeader()->nlmsg_len = | 
 |       NLMSG_ALIGN(MessageHeader()->nlmsg_len) + additional_data_length; | 
 | } | 
 |  | 
 | struct nlmsghdr* RtnetlinkMessage::MessageHeader() { | 
 |   return reinterpret_cast<struct nlmsghdr*>(message_[0].iov_base); | 
 | } | 
 |  | 
 | LinkMessage LinkMessage::New(RtnetlinkMessage::Operation request_operation, | 
 |                              uint16_t flags, uint32_t seq, uint32_t pid, | 
 |                              const struct ifinfomsg* interface_info_header) { | 
 |   uint16_t request_type; | 
 |   switch (request_operation) { | 
 |     case RtnetlinkMessage::Operation::NEW: | 
 |       request_type = RTM_NEWLINK; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::DEL: | 
 |       request_type = RTM_DELLINK; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::GET: | 
 |       request_type = RTM_GETLINK; | 
 |       break; | 
 |   } | 
 |   bool is_get = request_type == RTM_GETLINK; | 
 |  | 
 |   if (is_get) { | 
 |     struct rtgenmsg g = {AF_UNSPEC}; | 
 |     return LinkMessage(request_type, flags, seq, pid, &g, sizeof(g)); | 
 |   } | 
 |   return LinkMessage(request_type, flags, seq, pid, interface_info_header, | 
 |                      sizeof(struct ifinfomsg)); | 
 | } | 
 |  | 
 | AddressMessage AddressMessage::New( | 
 |     RtnetlinkMessage::Operation request_operation, uint16_t flags, uint32_t seq, | 
 |     uint32_t pid, const struct ifaddrmsg* interface_address_header) { | 
 |   uint16_t request_type; | 
 |   switch (request_operation) { | 
 |     case RtnetlinkMessage::Operation::NEW: | 
 |       request_type = RTM_NEWADDR; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::DEL: | 
 |       request_type = RTM_DELADDR; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::GET: | 
 |       request_type = RTM_GETADDR; | 
 |       break; | 
 |   } | 
 |   bool is_get = request_type == RTM_GETADDR; | 
 |  | 
 |   if (is_get) { | 
 |     struct rtgenmsg g = {AF_UNSPEC}; | 
 |     return AddressMessage(request_type, flags, seq, pid, &g, sizeof(g)); | 
 |   } | 
 |   return AddressMessage(request_type, flags, seq, pid, interface_address_header, | 
 |                         sizeof(struct ifaddrmsg)); | 
 | } | 
 |  | 
 | RouteMessage RouteMessage::New(RtnetlinkMessage::Operation request_operation, | 
 |                                uint16_t flags, uint32_t seq, uint32_t pid, | 
 |                                const struct rtmsg* route_message_header) { | 
 |   uint16_t request_type; | 
 |   switch (request_operation) { | 
 |     case RtnetlinkMessage::Operation::NEW: | 
 |       request_type = RTM_NEWROUTE; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::DEL: | 
 |       request_type = RTM_DELROUTE; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::GET: | 
 |       request_type = RTM_GETROUTE; | 
 |       break; | 
 |   } | 
 |   return RouteMessage(request_type, flags, seq, pid, route_message_header, | 
 |                       sizeof(struct rtmsg)); | 
 | } | 
 |  | 
 | RuleMessage RuleMessage::New(RtnetlinkMessage::Operation request_operation, | 
 |                              uint16_t flags, uint32_t seq, uint32_t pid, | 
 |                              const struct rtmsg* rule_message_header) { | 
 |   uint16_t request_type; | 
 |   switch (request_operation) { | 
 |     case RtnetlinkMessage::Operation::NEW: | 
 |       request_type = RTM_NEWRULE; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::DEL: | 
 |       request_type = RTM_DELRULE; | 
 |       break; | 
 |     case RtnetlinkMessage::Operation::GET: | 
 |       request_type = RTM_GETRULE; | 
 |       break; | 
 |   } | 
 |   return RuleMessage(request_type, flags, seq, pid, rule_message_header, | 
 |                      sizeof(rtmsg)); | 
 | } | 
 | }  // namespace quic |