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