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