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 <string>
24 #include <vector>
25
26 #include "common/libs/glog/logging.h"
27
28 namespace cvd {
29 namespace {
30 uint32_t kRequestSequenceNumber = 0;
31 } // namespace
32
SeqNo() const33 uint32_t NetlinkRequest::SeqNo() const {
34 return header_->nlmsg_seq;
35 }
36
AppendRaw(const void * data,size_t length)37 void* NetlinkRequest::AppendRaw(const void* data, size_t length) {
38 void* out = request_.end();
39
40 request_.Append(data, length);
41 int pad = RTA_ALIGN(length) - length;
42 if (pad > 0) {
43 request_.Resize(request_.size() + pad);
44 }
45
46 return out;
47 }
48
ReserveRaw(size_t length)49 void* NetlinkRequest::ReserveRaw(size_t length) {
50 void* out = request_.end();
51 request_.Resize(request_.size() + RTA_ALIGN(length));
52 return out;
53 }
54
AppendTag(uint16_t type,const void * data,uint16_t data_length)55 nlattr* NetlinkRequest::AppendTag(
56 uint16_t type, const void* data, uint16_t data_length) {
57 nlattr* attr = Reserve<nlattr>();
58 attr->nla_type = type;
59 attr->nla_len = RTA_LENGTH(data_length);
60 AppendRaw(data, data_length);
61 return attr;
62 }
63
NetlinkRequest(int32_t command,int32_t flags)64 NetlinkRequest::NetlinkRequest(int32_t command, int32_t flags)
65 : request_(512),
66 header_(Reserve<nlmsghdr>()) {
67 flags |= NLM_F_ACK | NLM_F_REQUEST;
68 header_->nlmsg_flags = flags;
69 header_->nlmsg_type = command;
70 header_->nlmsg_pid = getpid();
71 header_->nlmsg_seq = kRequestSequenceNumber++;
72 }
73
NetlinkRequest(NetlinkRequest && other)74 NetlinkRequest::NetlinkRequest(NetlinkRequest&& other) {
75 using std::swap;
76 swap(lists_, other.lists_);
77 swap(header_, other.header_);
78 request_.Swap(other.request_);
79 }
80
AddString(uint16_t type,const std::string & value)81 void NetlinkRequest::AddString(uint16_t type, const std::string& value) {
82 AppendTag(type, value.c_str(), value.length() + 1);
83 }
84
AddIfInfo(int32_t if_index,bool operational)85 void NetlinkRequest::AddIfInfo(int32_t if_index, bool operational) {
86 ifinfomsg* if_info = Reserve<ifinfomsg>();
87 if_info->ifi_family = AF_UNSPEC;
88 if_info->ifi_index = if_index;
89 if_info->ifi_flags = operational ? IFF_UP : 0;
90 if_info->ifi_change = IFF_UP;
91 }
92
AddAddrInfo(int32_t if_index,int prefix_len)93 void NetlinkRequest::AddAddrInfo(int32_t if_index, int prefix_len) {
94 ifaddrmsg* ad_info = Reserve<ifaddrmsg>();
95 ad_info->ifa_family = AF_INET;
96 ad_info->ifa_prefixlen = prefix_len;
97 ad_info->ifa_flags = IFA_F_PERMANENT | IFA_F_SECONDARY;
98 ad_info->ifa_scope = 0;
99 ad_info->ifa_index = if_index;
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 cvd
130