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 33 uint32_t NetlinkRequest::SeqNo() const { 34 return header_->nlmsg_seq; 35 } 36 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 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 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 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 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 81 void NetlinkRequest::AddString(uint16_t type, const std::string& value) { 82 AppendTag(type, value.c_str(), value.length() + 1); 83 } 84 85 void NetlinkRequest::AddInt32(uint16_t type, int32_t value) { 86 AppendTag(type, &value, sizeof(value)); 87 } 88 89 void NetlinkRequest::AddInt8(uint16_t type, int8_t value) { 90 AppendTag(type, &value, sizeof(value)); 91 } 92 93 void NetlinkRequest::AddIfInfo(int32_t if_index, bool operational) { 94 ifinfomsg* if_info = Reserve<ifinfomsg>(); 95 if_info->ifi_family = AF_UNSPEC; 96 if_info->ifi_index = if_index; 97 if_info->ifi_flags = operational ? IFF_UP : 0; 98 if_info->ifi_change = IFF_UP; 99 } 100 101 void NetlinkRequest::AddAddrInfo(int32_t if_index, int prefix_len) { 102 ifaddrmsg* ad_info = Reserve<ifaddrmsg>(); 103 ad_info->ifa_family = AF_INET; 104 ad_info->ifa_prefixlen = prefix_len; 105 ad_info->ifa_flags = IFA_F_PERMANENT | IFA_F_SECONDARY; 106 ad_info->ifa_scope = 0; 107 ad_info->ifa_index = if_index; 108 } 109 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 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 127 void* NetlinkRequest::RequestData() const { 128 // Update request length before reporting raw data. 129 header_->nlmsg_len = request_.size(); 130 return header_; 131 } 132 133 size_t NetlinkRequest::RequestLength() const { 134 return request_.size(); 135 } 136 137 } // namespace cvd 138