// // Copyright (C) 2012 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. // #ifndef SHILL_NET_NETLINK_ATTRIBUTE_H_ #define SHILL_NET_NETLINK_ATTRIBUTE_H_ #include <map> #include <string> #include <utility> #include <vector> #include <base/macros.h> #include "shill/net/attribute_list.h" #include "shill/net/byte_string.h" #include "shill/net/netlink_message.h" struct nlattr; namespace shill { // NetlinkAttribute is an abstract base class that describes an attribute in a // netlink-80211 message. Child classes are type-specific and will define // Get*Value and Set*Value methods (where * is the type). A second-level of // child classes exist for each individual attribute type. // // An attribute has an id (which is really an enumerated value), a data type, // and a value. In an nlattr (the underlying format for an attribute in a // message), the data is stored as a blob without type information; the writer // and reader of the attribute must agree on the data type. class SHILL_EXPORT NetlinkAttribute { public: enum Type { kTypeU8, kTypeU16, kTypeU32, kTypeU64, kTypeFlag, kTypeString, kTypeNested, kTypeRaw, kTypeError }; NetlinkAttribute(int id, const char* id_string, Type datatype, const char* datatype_string); virtual ~NetlinkAttribute() {} // Static factories generate the appropriate attribute object from the // raw nlattr data. static NetlinkAttribute* NewControlAttributeFromId(int id); static NetlinkAttribute* NewNl80211AttributeFromId( NetlinkMessage::MessageContext context, int id); virtual bool InitFromValue(const ByteString& input); // Accessors for the attribute's id and datatype information. int id() const { return id_; } virtual const char* id_string() const { return id_string_.c_str(); } Type datatype() const { return datatype_; } const char* datatype_string() const { return datatype_string_; } // Accessors. Return false if request is made on wrong type of attribute. virtual bool GetU8Value(uint8_t* value) const; virtual bool SetU8Value(uint8_t new_value); virtual bool GetU16Value(uint16_t* value) const; virtual bool SetU16Value(uint16_t value); virtual bool GetU32Value(uint32_t* value) const; virtual bool SetU32Value(uint32_t value); virtual bool GetU64Value(uint64_t* value) const; virtual bool SetU64Value(uint64_t value); virtual bool GetFlagValue(bool* value) const; virtual bool SetFlagValue(bool value); virtual bool GetStringValue(std::string* value) const; virtual bool SetStringValue(const std::string value); virtual bool GetNestedAttributeList(AttributeListRefPtr* value); virtual bool ConstGetNestedAttributeList( AttributeListConstRefPtr* value) const; virtual bool SetNestedHasAValue(); virtual bool GetRawValue(ByteString* value) const; virtual bool SetRawValue(const ByteString value); // Prints the attribute info -- for debugging. virtual void Print(int log_level, int indent) const; // Fill a string with characters that represents the value of the attribute. // If no attribute is found or if the datatype isn't trivially stringizable, // this method returns 'false' and |value| remains unchanged. virtual bool ToString(std::string* value) const = 0; // Writes the raw attribute data to a string. For debug. std::string RawToString() const; // Encodes the attribute suitably for the attributes in the payload portion // of a netlink message suitable for Sockets::Send. Return value is empty on // failure. virtual ByteString Encode() const = 0; bool has_a_value() const { return has_a_value_; } protected: // Builds a string to precede a printout of this attribute. std::string HeaderToPrint(int indent) const; // Encodes the attribute suitably for the attributes in the payload portion // of a netlink message suitable for Sockets::Send. Return value is empty on // failure. ByteString EncodeGeneric(const unsigned char* data, size_t num_bytes) const; // Attribute data (NOT including the nlattr header) corresponding to the // value in any of the child classes. ByteString data_; // True if a value has been assigned to the attribute; false, otherwise. bool has_a_value_; private: int id_; std::string id_string_; Type datatype_; const char* datatype_string_; DISALLOW_COPY_AND_ASSIGN(NetlinkAttribute); }; class NetlinkU8Attribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkU8Attribute(int id, const char* id_string) : NetlinkAttribute(id, id_string, kType, kMyTypeString) {} virtual bool InitFromValue(const ByteString& data); virtual bool GetU8Value(uint8_t* value) const; virtual bool SetU8Value(uint8_t new_value); virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; private: uint8_t value_; DISALLOW_COPY_AND_ASSIGN(NetlinkU8Attribute); }; class NetlinkU16Attribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkU16Attribute(int id, const char* id_string) : NetlinkAttribute(id, id_string, kType, kMyTypeString) {} virtual bool InitFromValue(const ByteString& data); virtual bool GetU16Value(uint16_t* value) const; virtual bool SetU16Value(uint16_t new_value); virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; private: uint16_t value_; DISALLOW_COPY_AND_ASSIGN(NetlinkU16Attribute); }; // Set SHILL_EXPORT to allow unit tests to instantiate these. class SHILL_EXPORT NetlinkU32Attribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkU32Attribute(int id, const char* id_string) : NetlinkAttribute(id, id_string, kType, kMyTypeString) {} virtual bool InitFromValue(const ByteString& data); virtual bool GetU32Value(uint32_t* value) const; virtual bool SetU32Value(uint32_t new_value); virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; private: uint32_t value_; DISALLOW_COPY_AND_ASSIGN(NetlinkU32Attribute); }; class NetlinkU64Attribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkU64Attribute(int id, const char* id_string) : NetlinkAttribute(id, id_string, kType, kMyTypeString) {} virtual bool InitFromValue(const ByteString& data); virtual bool GetU64Value(uint64_t* value) const; virtual bool SetU64Value(uint64_t new_value); virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; private: uint64_t value_; DISALLOW_COPY_AND_ASSIGN(NetlinkU64Attribute); }; class NetlinkFlagAttribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkFlagAttribute(int id, const char* id_string) : NetlinkAttribute(id, id_string, kType, kMyTypeString) {} virtual bool InitFromValue(const ByteString& data); virtual bool GetFlagValue(bool* value) const; virtual bool SetFlagValue(bool new_value); virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; private: bool value_; DISALLOW_COPY_AND_ASSIGN(NetlinkFlagAttribute); }; // Set SHILL_EXPORT to allow unit tests to instantiate these. class SHILL_EXPORT NetlinkStringAttribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkStringAttribute(int id, const char* id_string) : NetlinkAttribute(id, id_string, kType, kMyTypeString) {} virtual bool InitFromValue(const ByteString& data); virtual bool GetStringValue(std::string* value) const; virtual bool SetStringValue(const std::string new_value); virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; std::string value() const { return value_; } void set_value(const std::string& value) { value_ = value; } private: std::string value_; DISALLOW_COPY_AND_ASSIGN(NetlinkStringAttribute); }; // SSID attributes are just string attributes with different output semantics. class NetlinkSsidAttribute : public NetlinkStringAttribute { public: NetlinkSsidAttribute(int id, const char* id_string) : NetlinkStringAttribute(id, id_string) {} // NOTE: |ToString| or |Print| must be used for logging to allow scrubbing. virtual bool ToString(std::string* output) const; private: DISALLOW_COPY_AND_ASSIGN(NetlinkSsidAttribute); }; class NetlinkNestedAttribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkNestedAttribute(int id, const char* id_string); virtual bool InitFromValue(const ByteString& data); virtual bool GetNestedAttributeList(AttributeListRefPtr* value); virtual bool ConstGetNestedAttributeList( AttributeListConstRefPtr* value) const; virtual bool SetNestedHasAValue(); virtual void Print(int log_level, int indent) const; virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; protected: // Describes a single nested attribute. Provides the expected values and // type (including further nesting). Normally, an array of these, one for // each attribute at one level of nesting is presented, along with the data // to be parsed, to |InitNestedFromValue|. If the attributes on one level // represent an array, a single |NestedData| is provided and |is_array| is // set (note that one level of nesting either contains _only_ an array or // _no_ array). struct NestedData { typedef base::Callback<bool (AttributeList* list, size_t id, const std::string& attribute_name, ByteString data)> AttributeParser; typedef std::map<size_t, NestedData> NestedDataMap; NestedData(); NestedData(Type type, std::string attribute_name, bool is_array); NestedData(Type type, std::string attribute_name, bool is_array, const AttributeParser& parse_attribute); Type type; std::string attribute_name; NestedDataMap deeper_nesting; bool is_array; // Closure that overrides the usual parsing of this attribute. A non-NULL // value for |parse_attribute| will cause the software to ignore the other // members of the |NestedData| structure. AttributeParser parse_attribute; }; typedef std::pair<size_t, NestedData> AttrDataPair; // Some Nl80211 nested attributes are containers that do not have an actual // attribute id, but are nested in another attribute as array elements. // In the underlying netlink message, these attributes exist in their own // nested layer, and take on attribute ids equal to their index in the array. // For purposes of parsing these attributes, assign them an arbitrary // attribute id. static const size_t kArrayAttrEnumVal; // Builds an AttributeList (|list|) that contains all of the attriubtes in // |value|. |value| should contain the payload of the nested attribute // and not the nested attribute header itself; for the example of the nested // attribute NL80211_ATTR_CQM should contain: // nlattr::nla_type: NL80211_ATTR_CQM // nlattr::nla_len: 12 bytes // nlattr::nla_type: PKT_LOSS_EVENT (1st and only nested attribute) // nlattr::nla_len: 8 bytes // <data>: 0x32 // One can assemble (hence, disassemble) a set of child attributes under a // nested attribute parent as an array of elements or as a structure. // // The data is parsed using the expected configuration in |nested_template|. // If the code expects an array, it will pass a single template element and // mark that as an array. static bool InitNestedFromValue( const AttributeListRefPtr& list, const NestedData::NestedDataMap& templates, const ByteString& value); AttributeListRefPtr value_; NestedData::NestedDataMap nested_template_; private: // Helper functions used by InitNestedFromValue to add a single child // attribute to a nested attribute. static bool AddAttributeToNestedMap( const NetlinkNestedAttribute::NestedData::NestedDataMap& templates, const AttributeListRefPtr& list, int id, const ByteString& value); static bool AddAttributeToNestedArray( const NetlinkNestedAttribute::NestedData& array_template, const AttributeListRefPtr& list, int id, const ByteString& value); static bool AddAttributeToNestedInner( const NetlinkNestedAttribute::NestedData& nested_template, const std::string& attribute_name, const AttributeListRefPtr& list, int id, const ByteString& value); DISALLOW_COPY_AND_ASSIGN(NetlinkNestedAttribute); }; class NetlinkRawAttribute : public NetlinkAttribute { public: static const char kMyTypeString[]; static const Type kType; NetlinkRawAttribute(int id, const char* id_string) : NetlinkAttribute(id, id_string, kType, kMyTypeString) {} virtual bool InitFromValue(const ByteString& data); // Gets the value of the data (the header is not stored). virtual bool GetRawValue(ByteString* value) const; // Should set the value of the data (not the attribute header). virtual bool SetRawValue(const ByteString value); virtual bool ToString(std::string* value) const; virtual ByteString Encode() const; private: DISALLOW_COPY_AND_ASSIGN(NetlinkRawAttribute); }; class NetlinkAttributeGeneric : public NetlinkRawAttribute { public: explicit NetlinkAttributeGeneric(int id); virtual const char* id_string() const; private: std::string id_string_; DISALLOW_COPY_AND_ASSIGN(NetlinkAttributeGeneric); }; } // namespace shill #endif // SHILL_NET_NETLINK_ATTRIBUTE_H_