| // 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 <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 |