summaryrefslogtreecommitdiff
path: root/common/libs/net/netlink_request.cpp
blob: 501b2c35d142a31d9339793e30ae66cd7ed4842e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "common/libs/net/netlink_request.h"

#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <string.h>

#include <algorithm>
#include <string>
#include <vector>

#include "common/libs/glog/logging.h"

namespace cvd {
namespace {
uint32_t kRequestSequenceNumber = 0;
}  // namespace

uint32_t NetlinkRequest::SeqNo() const {
  return header_->nlmsg_seq;
}

void* NetlinkRequest::AppendRaw(const void* data, size_t length) {
  auto* output = static_cast<char*>(ReserveRaw(length));
  const auto* input = static_cast<const char*>(data);
  std::copy(input, input + length, output);
  return output;
}

void* NetlinkRequest::ReserveRaw(size_t length) {
  size_t original_size = request_.size();
  request_.resize(original_size + RTA_ALIGN(length), '\0');
  return reinterpret_cast<void*>(request_.data() + original_size);
}

nlattr* NetlinkRequest::AppendTag(
    uint16_t type, const void* data, uint16_t data_length) {
  nlattr* attr = Reserve<nlattr>();
  attr->nla_type = type;
  attr->nla_len = RTA_LENGTH(data_length);
  AppendRaw(data, data_length);
  return attr;
}

NetlinkRequest::NetlinkRequest(int32_t command, int32_t flags) {
  request_.reserve(512);
  header_ = Reserve<nlmsghdr>();
  flags |= NLM_F_ACK | NLM_F_REQUEST;
  header_->nlmsg_flags = flags;
  header_->nlmsg_type = command;
  header_->nlmsg_pid = getpid();
  header_->nlmsg_seq = kRequestSequenceNumber++;
}

NetlinkRequest::NetlinkRequest(NetlinkRequest&& other) {
  using std::swap;
  swap(lists_, other.lists_);
  swap(header_, other.header_);
  swap(request_, other.request_);
}

void NetlinkRequest::AddString(uint16_t type, const std::string& value) {
  AppendTag(type, value.c_str(), value.length() + 1);
}

void NetlinkRequest::AddIfInfo(int32_t if_index, bool operational) {
  ifinfomsg* if_info = Reserve<ifinfomsg>();
  if_info->ifi_family = AF_UNSPEC;
  if_info->ifi_index = if_index;
  if_info->ifi_flags = operational ? IFF_UP : 0;
  if_info->ifi_change = IFF_UP;
}

void NetlinkRequest::AddAddrInfo(int32_t if_index, int prefix_len) {
  ifaddrmsg* ad_info = Reserve<ifaddrmsg>();
  ad_info->ifa_family = AF_INET;
  ad_info->ifa_prefixlen = prefix_len;
  ad_info->ifa_flags = IFA_F_PERMANENT | IFA_F_SECONDARY;
  ad_info->ifa_scope = 0;
  ad_info->ifa_index = if_index;
}

void NetlinkRequest::PushList(uint16_t type) {
  int length = request_.size();
  nlattr* list = AppendTag(type, NULL, 0);
  lists_.push_back(std::make_pair(list, length));
}

void NetlinkRequest::PopList() {
  if (lists_.empty()) {
    LOG(ERROR) << "List pop with no lists left on stack.";
    return;
  }

  std::pair<nlattr*, int> list = lists_.back();
  lists_.pop_back();
  list.first->nla_len = request_.size() - list.second;
}

void* NetlinkRequest::RequestData() const {
  // Update request length before reporting raw data.
  header_->nlmsg_len = request_.size();
  return header_;
}

size_t NetlinkRequest::RequestLength() const {
  return request_.size();
}

}  // namespace cvd