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/netlink.h>
19 #include <linux/rtnetlink.h>
20 #include <net/if.h>
21 #include <string.h>
22 
23 #include <algorithm>
24 #include <string>
25 #include <vector>
26 
27 #include "android-base/logging.h"
28 
29 namespace cuttlefish {
30 namespace {
31 uint32_t kRequestSequenceNumber = 0;
32 }  // namespace
33 
SeqNo() const34 uint32_t NetlinkRequest::SeqNo() const {
35   return header_->nlmsg_seq;
36 }
37 
AppendRaw(const void * data,size_t length)38 void* NetlinkRequest::AppendRaw(const void* data, size_t length) {
39   auto* output = static_cast<char*>(ReserveRaw(length));
40   const auto* input = static_cast<const char*>(data);
41   std::copy(input, input + length, output);
42   return output;
43 }
44 
ReserveRaw(size_t length)45 void* NetlinkRequest::ReserveRaw(size_t length) {
46   size_t original_size = request_.size();
47   request_.resize(original_size + RTA_ALIGN(length), '\0');
48   return reinterpret_cast<void*>(request_.data() + original_size);
49 }
50 
AppendTag(uint16_t type,const void * data,uint16_t data_length)51 nlattr* NetlinkRequest::AppendTag(
52     uint16_t type, const void* data, uint16_t data_length) {
53   nlattr* attr = Reserve<nlattr>();
54   attr->nla_type = type;
55   attr->nla_len = RTA_LENGTH(data_length);
56   AppendRaw(data, data_length);
57   return attr;
58 }
59 
NetlinkRequest(int32_t command,int32_t flags)60 NetlinkRequest::NetlinkRequest(int32_t command, int32_t flags) {
61   request_.reserve(512);
62   header_ = Reserve<nlmsghdr>();
63   flags |= NLM_F_ACK | NLM_F_REQUEST;
64   header_->nlmsg_flags = flags;
65   header_->nlmsg_type = command;
66   header_->nlmsg_pid = getpid();
67   header_->nlmsg_seq = kRequestSequenceNumber++;
68 }
69 
NetlinkRequest(NetlinkRequest && other)70 NetlinkRequest::NetlinkRequest(NetlinkRequest&& other) {
71   using std::swap;
72   swap(lists_, other.lists_);
73   swap(header_, other.header_);
74   swap(request_, other.request_);
75 }
76 
AddString(uint16_t type,const std::string & value)77 void NetlinkRequest::AddString(uint16_t type, const std::string& value) {
78   AppendTag(type, value.c_str(), value.length() + 1);
79 }
80 
AddIfInfo(int32_t if_index,bool operational)81 void NetlinkRequest::AddIfInfo(int32_t if_index, bool operational) {
82   ifinfomsg* if_info = Reserve<ifinfomsg>();
83   if_info->ifi_family = AF_UNSPEC;
84   if_info->ifi_index = if_index;
85   if_info->ifi_flags = operational ? IFF_UP : 0;
86   if_info->ifi_change = IFF_UP;
87 }
88 
AddAddrInfo(int32_t if_index,int prefix_len)89 void NetlinkRequest::AddAddrInfo(int32_t if_index, int prefix_len) {
90   ifaddrmsg* ad_info = Reserve<ifaddrmsg>();
91   ad_info->ifa_family = AF_INET;
92   ad_info->ifa_prefixlen = prefix_len;
93   ad_info->ifa_flags = IFA_F_PERMANENT | IFA_F_SECONDARY;
94   ad_info->ifa_scope = 0;
95   ad_info->ifa_index = if_index;
96 }
97 
AddMacAddress(const std::array<unsigned char,6> & address)98 void NetlinkRequest::AddMacAddress(const std::array<unsigned char, 6>& address) {
99   AppendTag(IFLA_ADDRESS, address.data(), 6);
100 }
101 
PushList(uint16_t type)102 void NetlinkRequest::PushList(uint16_t type) {
103   int length = request_.size();
104   nlattr* list = AppendTag(type, NULL, 0);
105   lists_.push_back(std::make_pair(list, length));
106 }
107 
PopList()108 void NetlinkRequest::PopList() {
109   if (lists_.empty()) {
110     LOG(ERROR) << "List pop with no lists left on stack.";
111     return;
112   }
113 
114   std::pair<nlattr*, int> list = lists_.back();
115   lists_.pop_back();
116   list.first->nla_len = request_.size() - list.second;
117 }
118 
RequestData() const119 void* NetlinkRequest::RequestData() const {
120   // Update request length before reporting raw data.
121   header_->nlmsg_len = request_.size();
122   return header_;
123 }
124 
RequestLength() const125 size_t NetlinkRequest::RequestLength() const {
126   return request_.size();
127 }
128 
129 }  // namespace cuttlefish
130