blob: 294ffcfe700eba8e4915c4e00b7403398f0ae9c6 [file] [log] [blame]
// Copyright (c) 2012 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_NETLINK_ATTRIBUTE_H_
#define SHILL_NETLINK_ATTRIBUTE_H_
#include <netlink/attr.h>
#include <string>
#include <vector>
#include <base/basictypes.h>
#include "shill/attribute_list.h"
#include "shill/byte_string.h"
#include "shill/logging.h"
#include "shill/refptr_types.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 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(int id);
virtual bool InitFromNlAttr(const nlattr *data);
// 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_; }
// Wrappers for libnl parsers. Needed because, while |nla_get_*| don't
// change their arguments, these methods don't declare themselves as 'const'.
static char *NlaGetString(const nlattr *input) {
return nla_get_string(const_cast<nlattr *>(input));
}
static uint8_t NlaGetU8(const nlattr *input) {
return nla_get_u8(const_cast<nlattr *>(input));
}
static uint16_t NlaGetU16(const nlattr *input) {
return nla_get_u16(const_cast<nlattr *>(input));
}
static uint32_t NlaGetU32(const nlattr *input) {
return nla_get_u32(const_cast<nlattr *>(input));
}
static uint64_t NlaGetU64(const nlattr *input) {
return nla_get_u64(const_cast<nlattr *>(input));
}
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 InitFromNlAttr(const nlattr *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 InitFromNlAttr(const nlattr *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);
};
class 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 InitFromNlAttr(const nlattr *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 InitFromNlAttr(const nlattr *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 InitFromNlAttr(const nlattr *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);
};
class 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 InitFromNlAttr(const nlattr *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 InitFromNlAttr(const nlattr *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 |InitNestedFromNlAttr|. 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::vector<NestedData> NestedDataVector;
NestedData();
NestedData(uint16_t type, std::string attribute_name, bool is_array);
NestedData(uint16_t type, std::string attribute_name, bool is_array,
const AttributeParser &parse_attribute);
uint16_t type;
std::string attribute_name;
NestedDataVector 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;
};
NestedData::NestedDataVector nested_template_;
// Builds an AttributeList (|list|) that contains all of the attriubtes in
// |const_data|. |const_data| should point to the enclosing nested attribute
// header; for the example of the nested attribute NL80211_ATTR_CQM:
// nlattr::nla_type: NL80211_ATTR_CQM <-- const_data points here
// 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 InitNestedFromNlAttr(
AttributeList *list, const NestedData::NestedDataVector &templates,
const nlattr *const_data);
static bool ParseNestedArray(
AttributeList *list, const NestedData &templates,
const nlattr *const_data);
static bool ParseNestedStructure(
AttributeList *list, const NestedData::NestedDataVector &templates,
const nlattr *const_data);
// Helper function used by InitNestedFromNlAttr to add a single child
// attribute to a nested attribute.
static void AddAttributeToNested(AttributeList *list, uint16_t type, size_t i,
const std::string &attribute_name,
const nlattr &attr,
const NestedData &nested_data);
AttributeListRefPtr value_;
private:
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 InitFromNlAttr(const nlattr *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_NETLINK_ATTRIBUTE_H_