1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "common/libs/net/netlink_request.h"
17
18 #include <linux/if_addr.h>
19 #include <linux/if_link.h>
20 #include <linux/netlink.h>
21 #include <linux/rtnetlink.h>
22 #include <net/if.h>
23 #include <sys/socket.h>
24 #include <unistd.h>
25
26 #include <algorithm>
27 #include <array>
28 #include <cstdint> // for int32_t
29 #include <ostream> // for operator<<, basic_ostream
30 #include <string>
31 #include <type_traits> // for swap
32 #include <utility>
33 #include <vector>
34
35 #include "android-base/logging.h"
36
37 namespace cuttlefish {
38 namespace {
39 uint32_t kRequestSequenceNumber = 0;
40 } // namespace
41
SeqNo() const42 uint32_t NetlinkRequest::SeqNo() const {
43 return header_->nlmsg_seq;
44 }
45
AppendRaw(const void * data,size_t length)46 void* NetlinkRequest::AppendRaw(const void* data, size_t length) {
47 auto* output = static_cast<char*>(ReserveRaw(length));
48 const auto* input = static_cast<const char*>(data);
49 std::copy(input, input + length, output);
50 return output;
51 }
52
ReserveRaw(size_t length)53 void* NetlinkRequest::ReserveRaw(size_t length) {
54 size_t original_size = request_.size();
55 request_.resize(original_size + RTA_ALIGN(length), '\0');
56 return reinterpret_cast<void*>(request_.data() + original_size);
57 }
58
AppendTag(uint16_t type,const void * data,uint16_t data_length)59 nlattr* NetlinkRequest::AppendTag(
60 uint16_t type, const void* data, uint16_t data_length) {
61 nlattr* attr = Reserve<nlattr>();
62 attr->nla_type = type;
63 attr->nla_len = RTA_LENGTH(data_length);
64 AppendRaw(data, data_length);
65 return attr;
66 }
67
NetlinkRequest(int32_t command,int32_t flags)68 NetlinkRequest::NetlinkRequest(int32_t command, int32_t flags) {
69 request_.reserve(512);
70 header_ = Reserve<nlmsghdr>();
71 flags |= NLM_F_ACK | NLM_F_REQUEST;
72 header_->nlmsg_flags = flags;
73 header_->nlmsg_type = command;
74 header_->nlmsg_pid = getpid();
75 header_->nlmsg_seq = kRequestSequenceNumber++;
76 }
77
NetlinkRequest(NetlinkRequest && other)78 NetlinkRequest::NetlinkRequest(NetlinkRequest&& other) {
79 using std::swap;
80 swap(lists_, other.lists_);
81 swap(header_, other.header_);
82 swap(request_, other.request_);
83 }
84
AddString(uint16_t type,const std::string & value)85 void NetlinkRequest::AddString(uint16_t type, const std::string& value) {
86 AppendTag(type, value.c_str(), value.length() + 1);
87 }
88
AddIfInfo(int32_t if_index,bool operational)89 void NetlinkRequest::AddIfInfo(int32_t if_index, bool operational) {
90 ifinfomsg* if_info = Reserve<ifinfomsg>();
91 if_info->ifi_family = AF_UNSPEC;
92 if_info->ifi_index = if_index;
93 if_info->ifi_flags = operational ? IFF_UP : 0;
94 if_info->ifi_change = IFF_UP;
95 }
96
AddAddrInfo(int32_t if_index,int prefix_len)97 void NetlinkRequest::AddAddrInfo(int32_t if_index, int prefix_len) {
98 ifaddrmsg* ad_info = Reserve<ifaddrmsg>();
99 ad_info->ifa_family = AF_INET;
100 ad_info->ifa_prefixlen = prefix_len;
101 ad_info->ifa_flags = IFA_F_PERMANENT | IFA_F_SECONDARY;
102 ad_info->ifa_scope = 0;
103 ad_info->ifa_index = if_index;
104 }
105
AddMacAddress(const std::array<unsigned char,6> & address)106 void NetlinkRequest::AddMacAddress(const std::array<unsigned char, 6>& address) {
107 AppendTag(IFLA_ADDRESS, address.data(), 6);
108 }
109
PushList(uint16_t type)110 void NetlinkRequest::PushList(uint16_t type) {
111 int length = request_.size();
112 nlattr* list = AppendTag(type, NULL, 0);
113 lists_.push_back(std::make_pair(list, length));
114 }
115
PopList()116 void NetlinkRequest::PopList() {
117 if (lists_.empty()) {
118 LOG(ERROR) << "List pop with no lists left on stack.";
119 return;
120 }
121
122 std::pair<nlattr*, int> list = lists_.back();
123 lists_.pop_back();
124 list.first->nla_len = request_.size() - list.second;
125 }
126
RequestData() const127 void* NetlinkRequest::RequestData() const {
128 // Update request length before reporting raw data.
129 header_->nlmsg_len = request_.size();
130 return header_;
131 }
132
RequestLength() const133 size_t NetlinkRequest::RequestLength() const {
134 return request_.size();
135 }
136
137 } // namespace cuttlefish
138