/* * 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 <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) { void* out = request_.end(); request_.Append(data, length); int pad = RTA_ALIGN(length) - length; if (pad > 0) { request_.Resize(request_.size() + pad); } return out; } void* NetlinkRequest::ReserveRaw(size_t length) { void* out = request_.end(); request_.Resize(request_.size() + RTA_ALIGN(length)); return out; } 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_(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_); request_.Swap(other.request_); } void NetlinkRequest::AddString(uint16_t type, const std::string& value) { AppendTag(type, value.c_str(), value.length() + 1); } void NetlinkRequest::AddInt32(uint16_t type, int32_t value) { AppendTag(type, &value, sizeof(value)); } void NetlinkRequest::AddInt8(uint16_t type, int8_t value) { AppendTag(type, &value, sizeof(value)); } 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