xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/platform/rtnetlink_message.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium 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 "quiche/quic/qbone/platform/rtnetlink_message.h"
6 
7 #include <utility>
8 
9 namespace quic {
10 
RtnetlinkMessage(uint16_t type,uint16_t flags,uint32_t seq,uint32_t pid,const void * payload_header,size_t payload_header_length)11 RtnetlinkMessage::RtnetlinkMessage(uint16_t type, uint16_t flags, uint32_t seq,
12                                    uint32_t pid, const void* payload_header,
13                                    size_t payload_header_length) {
14   auto* buf = new uint8_t[NLMSG_SPACE(payload_header_length)];
15   memset(buf, 0, NLMSG_SPACE(payload_header_length));
16 
17   auto* message_header = reinterpret_cast<struct nlmsghdr*>(buf);
18   message_header->nlmsg_len = NLMSG_LENGTH(payload_header_length);
19   message_header->nlmsg_type = type;
20   message_header->nlmsg_flags = flags;
21   message_header->nlmsg_seq = seq;
22   message_header->nlmsg_pid = pid;
23 
24   if (payload_header != nullptr) {
25     memcpy(NLMSG_DATA(message_header), payload_header, payload_header_length);
26   }
27   message_.push_back({buf, NLMSG_SPACE(payload_header_length)});
28 }
29 
~RtnetlinkMessage()30 RtnetlinkMessage::~RtnetlinkMessage() {
31   for (const auto& iov : message_) {
32     delete[] reinterpret_cast<uint8_t*>(iov.iov_base);
33   }
34 }
35 
AppendAttribute(uint16_t type,const void * data,uint16_t data_length)36 void RtnetlinkMessage::AppendAttribute(uint16_t type, const void* data,
37                                        uint16_t data_length) {
38   auto* buf = new uint8_t[RTA_SPACE(data_length)];
39   memset(buf, 0, RTA_SPACE(data_length));
40 
41   auto* rta = reinterpret_cast<struct rtattr*>(buf);
42   static_assert(sizeof(uint16_t) == sizeof(rta->rta_len),
43                 "struct rtattr uses unsigned short, it's no longer 16bits");
44   static_assert(sizeof(uint16_t) == sizeof(rta->rta_type),
45                 "struct rtattr uses unsigned short, it's no longer 16bits");
46 
47   rta->rta_len = RTA_LENGTH(data_length);
48   rta->rta_type = type;
49   memcpy(RTA_DATA(rta), data, data_length);
50 
51   message_.push_back({buf, RTA_SPACE(data_length)});
52   AdjustMessageLength(rta->rta_len);
53 }
54 
BuildIoVec() const55 std::unique_ptr<struct iovec[]> RtnetlinkMessage::BuildIoVec() const {
56   auto message = std::make_unique<struct iovec[]>(message_.size());
57   int idx = 0;
58   for (const auto& vec : message_) {
59     message[idx++] = vec;
60   }
61   return message;
62 }
63 
IoVecSize() const64 size_t RtnetlinkMessage::IoVecSize() const { return message_.size(); }
65 
AdjustMessageLength(size_t additional_data_length)66 void RtnetlinkMessage::AdjustMessageLength(size_t additional_data_length) {
67   MessageHeader()->nlmsg_len =
68       NLMSG_ALIGN(MessageHeader()->nlmsg_len) + additional_data_length;
69 }
70 
MessageHeader()71 struct nlmsghdr* RtnetlinkMessage::MessageHeader() {
72   return reinterpret_cast<struct nlmsghdr*>(message_[0].iov_base);
73 }
74 
New(RtnetlinkMessage::Operation request_operation,uint16_t flags,uint32_t seq,uint32_t pid,const struct ifinfomsg * interface_info_header)75 LinkMessage LinkMessage::New(RtnetlinkMessage::Operation request_operation,
76                              uint16_t flags, uint32_t seq, uint32_t pid,
77                              const struct ifinfomsg* interface_info_header) {
78   uint16_t request_type;
79   switch (request_operation) {
80     case RtnetlinkMessage::Operation::NEW:
81       request_type = RTM_NEWLINK;
82       break;
83     case RtnetlinkMessage::Operation::DEL:
84       request_type = RTM_DELLINK;
85       break;
86     case RtnetlinkMessage::Operation::GET:
87       request_type = RTM_GETLINK;
88       break;
89   }
90   bool is_get = request_type == RTM_GETLINK;
91 
92   if (is_get) {
93     struct rtgenmsg g = {AF_UNSPEC};
94     return LinkMessage(request_type, flags, seq, pid, &g, sizeof(g));
95   }
96   return LinkMessage(request_type, flags, seq, pid, interface_info_header,
97                      sizeof(struct ifinfomsg));
98 }
99 
New(RtnetlinkMessage::Operation request_operation,uint16_t flags,uint32_t seq,uint32_t pid,const struct ifaddrmsg * interface_address_header)100 AddressMessage AddressMessage::New(
101     RtnetlinkMessage::Operation request_operation, uint16_t flags, uint32_t seq,
102     uint32_t pid, const struct ifaddrmsg* interface_address_header) {
103   uint16_t request_type;
104   switch (request_operation) {
105     case RtnetlinkMessage::Operation::NEW:
106       request_type = RTM_NEWADDR;
107       break;
108     case RtnetlinkMessage::Operation::DEL:
109       request_type = RTM_DELADDR;
110       break;
111     case RtnetlinkMessage::Operation::GET:
112       request_type = RTM_GETADDR;
113       break;
114   }
115   bool is_get = request_type == RTM_GETADDR;
116 
117   if (is_get) {
118     struct rtgenmsg g = {AF_UNSPEC};
119     return AddressMessage(request_type, flags, seq, pid, &g, sizeof(g));
120   }
121   return AddressMessage(request_type, flags, seq, pid, interface_address_header,
122                         sizeof(struct ifaddrmsg));
123 }
124 
New(RtnetlinkMessage::Operation request_operation,uint16_t flags,uint32_t seq,uint32_t pid,const struct rtmsg * route_message_header)125 RouteMessage RouteMessage::New(RtnetlinkMessage::Operation request_operation,
126                                uint16_t flags, uint32_t seq, uint32_t pid,
127                                const struct rtmsg* route_message_header) {
128   uint16_t request_type;
129   switch (request_operation) {
130     case RtnetlinkMessage::Operation::NEW:
131       request_type = RTM_NEWROUTE;
132       break;
133     case RtnetlinkMessage::Operation::DEL:
134       request_type = RTM_DELROUTE;
135       break;
136     case RtnetlinkMessage::Operation::GET:
137       request_type = RTM_GETROUTE;
138       break;
139   }
140   return RouteMessage(request_type, flags, seq, pid, route_message_header,
141                       sizeof(struct rtmsg));
142 }
143 
New(RtnetlinkMessage::Operation request_operation,uint16_t flags,uint32_t seq,uint32_t pid,const struct rtmsg * rule_message_header)144 RuleMessage RuleMessage::New(RtnetlinkMessage::Operation request_operation,
145                              uint16_t flags, uint32_t seq, uint32_t pid,
146                              const struct rtmsg* rule_message_header) {
147   uint16_t request_type;
148   switch (request_operation) {
149     case RtnetlinkMessage::Operation::NEW:
150       request_type = RTM_NEWRULE;
151       break;
152     case RtnetlinkMessage::Operation::DEL:
153       request_type = RTM_DELRULE;
154       break;
155     case RtnetlinkMessage::Operation::GET:
156       request_type = RTM_GETRULE;
157       break;
158   }
159   return RuleMessage(request_type, flags, seq, pid, rule_message_header,
160                      sizeof(rtmsg));
161 }
162 }  // namespace quic
163