blob: 26f363733a05da24cd348cccafa3d53b3826656d [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHILL_NET_NETLINK_ATTRIBUTE_H_
#define SHILL_NET_NETLINK_ATTRIBUTE_H_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <base/callback.h>
#include <base/macros.h>
#include "shill/net/attribute_list.h"
#include "shill/net/byte_string.h"
#include "shill/net/netlink_message.h"
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);
NetlinkAttribute(const NetlinkAttribute&) = delete;
NetlinkAttribute& operator=(const NetlinkAttribute&) = delete;
virtual ~NetlinkAttribute() = default;
// Static factories generate the appropriate attribute object from the
// raw nlattr data.
static std::unique_ptr<NetlinkAttribute> NewControlAttributeFromId(int id);
static std::unique_ptr<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_;
};
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) {}
NetlinkU8Attribute(const NetlinkU8Attribute&) = delete;
NetlinkU8Attribute& operator=(const NetlinkU8Attribute&) = delete;
bool InitFromValue(const ByteString& data) override;
bool GetU8Value(uint8_t* value) const override;
bool SetU8Value(uint8_t new_value) override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
private:
uint8_t value_;
};
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) {}
NetlinkU16Attribute(const NetlinkU16Attribute&) = delete;
NetlinkU16Attribute& operator=(const NetlinkU16Attribute&) = delete;
bool InitFromValue(const ByteString& data) override;
bool GetU16Value(uint16_t* value) const override;
bool SetU16Value(uint16_t new_value) override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
private:
uint16_t value_;
};
// 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) {}
NetlinkU32Attribute(const NetlinkU32Attribute&) = delete;
NetlinkU32Attribute& operator=(const NetlinkU32Attribute&) = delete;
bool InitFromValue(const ByteString& data) override;
bool GetU32Value(uint32_t* value) const override;
bool SetU32Value(uint32_t new_value) override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
private:
uint32_t value_;
};
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) {}
NetlinkU64Attribute(const NetlinkU64Attribute&) = delete;
NetlinkU64Attribute& operator=(const NetlinkU64Attribute&) = delete;
bool InitFromValue(const ByteString& data) override;
bool GetU64Value(uint64_t* value) const override;
bool SetU64Value(uint64_t new_value) override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
private:
uint64_t value_;
};
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) {}
NetlinkFlagAttribute(const NetlinkFlagAttribute&) = delete;
NetlinkFlagAttribute& operator=(const NetlinkFlagAttribute&) = delete;
bool InitFromValue(const ByteString& data) override;
bool GetFlagValue(bool* value) const override;
bool SetFlagValue(bool new_value) override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
private:
bool value_;
};
// 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) {}
NetlinkStringAttribute(const NetlinkStringAttribute&) = delete;
NetlinkStringAttribute& operator=(const NetlinkStringAttribute&) = delete;
bool InitFromValue(const ByteString& data) override;
bool GetStringValue(std::string* value) const override;
bool SetStringValue(const std::string& new_value) override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
std::string value() const { return value_; }
void set_value(const std::string& value) { value_ = value; }
private:
std::string value_;
};
// 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) {}
NetlinkSsidAttribute(const NetlinkSsidAttribute&) = delete;
NetlinkSsidAttribute& operator=(const NetlinkSsidAttribute&) = delete;
// NOTE: |ToString| or |Print| must be used for logging to allow scrubbing.
bool ToString(std::string* output) const override;
};
class NetlinkNestedAttribute : public NetlinkAttribute {
public:
static const char kMyTypeString[];
static const Type kType;
NetlinkNestedAttribute(int id, const char* id_string);
NetlinkNestedAttribute(const NetlinkNestedAttribute&) = delete;
NetlinkNestedAttribute& operator=(const NetlinkNestedAttribute&) = delete;
bool InitFromValue(const ByteString& data) override;
bool GetNestedAttributeList(AttributeListRefPtr* value) override;
bool ConstGetNestedAttributeList(
AttributeListConstRefPtr* value) const override;
bool SetNestedHasAValue() override;
void Print(int log_level, int indent) const override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
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 {
using AttributeParser =
base::Callback<bool(AttributeList* list,
size_t id,
const std::string& attribute_name,
ByteString data)>;
using NestedDataMap = std::map<size_t, NestedData>;
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;
};
using AttrDataPair = std::pair<size_t, NestedData>;
// 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);
};
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) {}
NetlinkRawAttribute(const NetlinkRawAttribute&) = delete;
NetlinkRawAttribute& operator=(const NetlinkRawAttribute&) = delete;
bool InitFromValue(const ByteString& data) override;
// Gets the value of the data (the header is not stored).
bool GetRawValue(ByteString* value) const override;
// Should set the value of the data (not the attribute header).
bool SetRawValue(const ByteString value) override;
bool ToString(std::string* value) const override;
ByteString Encode() const override;
};
class NetlinkAttributeGeneric : public NetlinkRawAttribute {
public:
explicit NetlinkAttributeGeneric(int id);
NetlinkAttributeGeneric(const NetlinkAttributeGeneric&) = delete;
NetlinkAttributeGeneric& operator=(const NetlinkAttributeGeneric&) = delete;
const char* id_string() const override;
private:
std::string id_string_;
};
} // namespace shill
#endif // SHILL_NET_NETLINK_ATTRIBUTE_H_