| /* |
| * Copyright (C) 2020 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 <libnetdevice/printer.h> |
| |
| #include "common.h" |
| #include "protocols/all.h" |
| |
| #include <android-base/logging.h> |
| #include <libnetdevice/nlbuf.h> |
| |
| #include <algorithm> |
| #include <iomanip> |
| #include <sstream> |
| |
| namespace android::netdevice { |
| |
| static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags) { |
| bool first = true; |
| auto printFlag = [&ss, &first, &nlmsg_flags](__u16 flag, const std::string& name) { |
| if (!(nlmsg_flags & flag)) return; |
| nlmsg_flags &= ~flag; |
| |
| if (first) { |
| first = false; |
| } else { |
| ss << '|'; |
| } |
| |
| ss << name; |
| }; |
| printFlag(NLM_F_REQUEST, "REQUEST"); |
| printFlag(NLM_F_MULTI, "MULTI"); |
| printFlag(NLM_F_ACK, "ACK"); |
| printFlag(NLM_F_ECHO, "ECHO"); |
| printFlag(NLM_F_DUMP_INTR, "DUMP_INTR"); |
| printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED"); |
| |
| // TODO(twasilczyk): print flags depending on request type |
| printFlag(NLM_F_ROOT, "ROOT-REPLACE"); |
| printFlag(NLM_F_MATCH, "MATCH-EXCL"); |
| printFlag(NLM_F_ATOMIC, "ATOMIC-CREATE"); |
| printFlag(NLM_F_APPEND, "APPEND"); |
| |
| if (nlmsg_flags != 0) { |
| if (!first) ss << '|'; |
| ss << std::hex << nlmsg_flags << std::dec; |
| } |
| } |
| |
| static void toStream(std::stringstream& ss, const nlbuf<uint8_t> data) { |
| ss << std::hex; |
| int i = 0; |
| for (const auto byte : data.getRaw()) { |
| if (i++ > 0) ss << ' '; |
| ss << std::setw(2) << unsigned(byte); |
| } |
| ss << std::dec; |
| } |
| |
| static void toStream(std::stringstream& ss, const nlbuf<nlattr> attr, |
| const protocols::AttributeMap& attrMap) { |
| using DataType = protocols::AttributeDefinition::DataType; |
| const auto attrtype = attrMap[attr->nla_type]; |
| |
| ss << attrtype.name << ": "; |
| switch (attrtype.dataType) { |
| case DataType::Raw: { |
| toStream(ss, attr.data<uint8_t>()); |
| break; |
| } |
| case DataType::Nested: { |
| ss << '{'; |
| bool first = true; |
| for (auto childattr : attr.data<nlattr>()) { |
| if (!first) ss << ", "; |
| first = false; |
| toStream(ss, childattr, attrtype.subTypes); |
| } |
| ss << '}'; |
| break; |
| } |
| case DataType::String: { |
| const auto str = attr.data<char>().getRaw(); |
| ss << '"' << sanitize({str.ptr(), str.len()}) << '"'; |
| break; |
| } |
| case DataType::Uint: { |
| ss << attr.data<uint32_t>().copyFirst(); |
| break; |
| } |
| } |
| } |
| |
| static std::string toString(const nlbuf<nlmsghdr> hdr, int protocol) { |
| if (!hdr.firstOk()) return "nlmsg{buffer overflow}"; |
| |
| std::stringstream ss; |
| ss << std::setfill('0'); |
| |
| auto protocolMaybe = protocols::get(protocol); |
| if (!protocolMaybe.has_value()) { |
| ss << "nlmsg{protocol=" << protocol << "}"; |
| return ss.str(); |
| } |
| protocols::NetlinkProtocol& protocolDescr = *protocolMaybe; |
| |
| auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type); |
| const auto msgTypeName = msgDescMaybe.has_value() |
| ? msgDescMaybe->get().getMessageName(hdr->nlmsg_type) |
| : std::to_string(hdr->nlmsg_type); |
| |
| ss << "nlmsg{" << protocolDescr.getName() << " "; |
| |
| ss << "hdr={"; |
| ss << "type=" << msgTypeName; |
| if (hdr->nlmsg_flags != 0) { |
| ss << ", flags="; |
| flagsToStream(ss, hdr->nlmsg_flags); |
| } |
| if (hdr->nlmsg_seq != 0) ss << ", seq=" << hdr->nlmsg_seq; |
| if (hdr->nlmsg_pid != 0) ss << ", pid=" << hdr->nlmsg_pid; |
| |
| ss << ", crc=" << std::hex << std::setw(4) << crc16(hdr.data<uint8_t>()) << std::dec; |
| ss << "} "; |
| |
| if (!msgDescMaybe.has_value()) { |
| toStream(ss, hdr.data<uint8_t>()); |
| } else { |
| const protocols::MessageDescriptor& msgDesc = *msgDescMaybe; |
| msgDesc.dataToStream(ss, hdr); |
| |
| bool first = true; |
| for (auto attr : hdr.data<nlattr>(msgDesc.getContentsSize())) { |
| if (first) { |
| ss << " attributes: {"; |
| first = false; |
| } else { |
| ss << ", "; |
| } |
| toStream(ss, attr, msgDesc.getAttributeMap()); |
| } |
| if (!first) ss << '}'; |
| } |
| |
| ss << "}"; |
| |
| return ss.str(); |
| } |
| |
| std::string toString(const nlmsghdr* hdr, size_t bufLen, int protocol) { |
| return toString({hdr, bufLen}, protocol); |
| } |
| |
| } // namespace android::netdevice |