1 /* 2 * Copyright (C) 2020 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 #pragma once 18 19 #include <libnl++/Buffer.h> 20 #include <libnl++/types.h> 21 22 #include <map> 23 #include <sstream> 24 #include <variant> 25 26 namespace android::nl::protocols { 27 28 struct AttributeDefinition; 29 30 /** 31 * Mapping between nlattrtype_t identifier and attribute definition. 32 * 33 * The map contains values for all nlattrtype_t identifiers - if some is missing, a generic 34 * definition with a identifier as its name will be generated. 35 * 36 * It's possible to define a default attribute to return instead of to_string of its identifier 37 * (useful for nested attribute lists). In such case, an entry with id=std::nullopt needs to be 38 * present in the map. 39 */ 40 class AttributeMap : private std::map<std::optional<nlattrtype_t>, AttributeDefinition> { 41 public: 42 using std::map<std::optional<nlattrtype_t>, AttributeDefinition>::value_type; 43 44 AttributeMap(const std::initializer_list<value_type> attrTypes); 45 46 const AttributeDefinition operator[](nlattrtype_t nla_type) const; 47 }; 48 49 /** 50 * Attribute definition. 51 * 52 * Describes the name and type (optionally sub types, in case of Nested attribute) 53 * for a given message attribute. 54 */ 55 struct AttributeDefinition { 56 enum class DataType : uint8_t { 57 /** 58 * Binary blob (or attribute of unknown type). 59 */ 60 Raw, 61 62 /** 63 * Nested attribute (with or without NLA_F_NESTED). 64 */ 65 Nested, 66 67 /** 68 * Non-null terminated string. 69 * 70 * The length of the string is determined by the size of an attribute. 71 */ 72 String, 73 74 /** 75 * Null terminated string. 76 */ 77 StringNul, 78 79 /** 80 * Unsigned integer of size 8, 16, 32 or 64 bits. 81 */ 82 Uint, 83 84 /** 85 * Structure which printer is defined in ops ToStream variant. 86 */ 87 Struct, 88 89 /** 90 * Flag attribute. 91 * 92 * The attribute doesn't have any contents. The flag is set when the attribute is present, 93 * it's not when it's absent from attribute list. 94 */ 95 Flag, 96 }; 97 enum class Flags : uint8_t { 98 Verbose = (1 << 0), 99 }; 100 using ToStream = std::function<void(std::stringstream& ss, const Buffer<nlattr> attr)>; 101 102 std::string name; 103 DataType dataType = DataType::Raw; 104 std::variant<AttributeMap, ToStream> ops = AttributeMap{}; 105 106 /** 107 * Attribute flags. 108 * 109 * It's not really a bitmask flag set (since you are not supposed to compare enum class by 110 * bitmask), but std::set<Flags> bumps compile time from 16s to 3m. Let's leave it as-is for 111 * now and revisit if we get some flags that can be used in pairs. When it happens, review all 112 * uses of the flags field to include the "&" operator and not "==". 113 */ 114 Flags flags = {}; 115 }; 116 117 /** 118 * General message type's kind. 119 * 120 * For example, RTM_NEWLINK is a NEW kind. For details, please see "Flags values" 121 * section in linux/netlink.h. 122 */ 123 enum class MessageGenre { 124 Unknown, 125 Get, 126 New, 127 Delete, 128 Ack, 129 }; 130 131 /** 132 * Message family descriptor. 133 * 134 * Describes the structure of all message types with the same header and attributes. 135 */ 136 class MessageDescriptor { 137 public: 138 struct MessageDetails { 139 std::string name; 140 MessageGenre genre; 141 }; 142 typedef std::map<nlmsgtype_t, MessageDetails> MessageDetailsMap; 143 144 public: 145 virtual ~MessageDescriptor(); 146 147 size_t getContentsSize() const; 148 const MessageDetailsMap& getMessageDetailsMap() const; 149 const AttributeMap& getAttributeMap() const; 150 MessageDetails getMessageDetails(nlmsgtype_t msgtype) const; 151 virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0; 152 153 /** 154 * Message tracking for stateful protocols (such as NETLINK_GENERIC). 155 * 156 * \param hdr Message to track 157 */ 158 virtual void track(const Buffer<nlmsghdr> hdr); 159 160 static MessageDetails getMessageDetails( 161 const std::optional<std::reference_wrapper<MessageDescriptor>>& msgDescMaybe, 162 nlmsgtype_t msgtype); 163 164 protected: 165 MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails, 166 const AttributeMap& attrTypes, size_t contentsSize); 167 168 private: 169 const std::string mName; 170 const size_t mContentsSize; 171 const MessageDetailsMap mMessageDetails; 172 const AttributeMap mAttributeMap; 173 }; 174 175 /** 176 * Message definition template. 177 * 178 * A convenience initialization helper of a message descriptor. 179 */ 180 template <typename T> 181 class MessageDefinition : public MessageDescriptor { 182 public: 183 MessageDefinition( // 184 const std::string& name, 185 const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet, 186 const AttributeMap& attrTypes = {}) MessageDescriptor(name,msgDet,attrTypes,sizeof (T))187 : MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {} 188 dataToStream(std::stringstream & ss,const Buffer<nlmsghdr> hdr)189 void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override { 190 const auto& [ok, msg] = hdr.data<T>().getFirst(); 191 if (!ok) { 192 ss << "{incomplete payload}"; 193 return; 194 } 195 196 toStream(ss, msg); 197 } 198 199 protected: 200 virtual void toStream(std::stringstream& ss, const T& data) const = 0; 201 }; 202 203 } // namespace android::nl::protocols 204