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 17 #include "netlinkmessage.h" 18 19 #include "log.h" 20 21 #include <linux/netlink.h> 22 #include <linux/rtnetlink.h> 23 #include <sys/types.h> 24 #include <unistd.h> 25 26 size_t getSpaceForMessageType(uint16_t type) { 27 switch (type) { 28 case RTM_NEWLINK: 29 case RTM_GETLINK: 30 return NLMSG_SPACE(sizeof(ifinfomsg)); 31 default: 32 return 0; 33 } 34 } 35 36 NetlinkMessage::NetlinkMessage(uint16_t type, 37 uint32_t sequence) 38 : mData(getSpaceForMessageType(type), 0) { 39 40 auto header = reinterpret_cast<nlmsghdr*>(mData.data()); 41 header->nlmsg_len = mData.size(); 42 header->nlmsg_flags = NLM_F_REQUEST; 43 header->nlmsg_type = type; 44 header->nlmsg_seq = sequence; 45 header->nlmsg_pid = getpid(); 46 } 47 48 NetlinkMessage::NetlinkMessage(const char* data, size_t size) 49 : mData(data, data + size) { 50 } 51 52 bool NetlinkMessage::getAttribute(int attributeId, void* data, size_t size) const { 53 const void* value = nullptr; 54 uint16_t attrSize = 0; 55 if (!findAttribute(attributeId, &value, &attrSize)) { 56 return false; 57 } 58 if (size > attrSize) { 59 return false; 60 } 61 memcpy(data, value, size); 62 return true; 63 } 64 65 uint16_t NetlinkMessage::type() const { 66 auto header = reinterpret_cast<const nlmsghdr*>(mData.data()); 67 return header->nlmsg_type; 68 } 69 70 uint32_t NetlinkMessage::sequence() const { 71 auto header = reinterpret_cast<const nlmsghdr*>(mData.data()); 72 return header->nlmsg_seq; 73 } 74 75 bool NetlinkMessage::findAttribute(int attributeId, 76 const void** value, 77 uint16_t* size) const { 78 const uint8_t* end = mData.data() + mData.size(); 79 size_t attrOffset = getSpaceForMessageType(type()); 80 if (attrOffset == 0) { 81 return false; 82 } 83 const uint8_t* attribute = mData.data() + attrOffset; 84 while (attribute < end) { 85 auto header = reinterpret_cast<const nlattr*>(attribute); 86 if (header->nla_len == 0) { 87 // The length should include the header so the length should always 88 // be greater than zero. If it doesn't we're going to end up looping 89 // forever so ignore this. 90 return false; 91 } 92 if (header->nla_type == attributeId) { 93 *value = attribute + NLA_HDRLEN; 94 *size = header->nla_len; 95 return true; 96 } 97 attribute += header->nla_len; 98 } 99 return false; 100 } 101