Merge changes I56edff81,I6839a899

* changes:
  Print error names instead of numbers
  Implement NL80211 protocol printer
This commit is contained in:
TreeHugger Robot 2020-12-09 19:01:46 +00:00 committed by Android (Google) Code Review
commit 58a92454ba
18 changed files with 1390 additions and 57 deletions

View file

@ -25,6 +25,7 @@ cc_library_static {
"protocols/generic/Generic.cpp",
"protocols/generic/GenericMessageBase.cpp",
"protocols/generic/Unknown.cpp",
"protocols/generic/families/Nl80211.cpp",
"protocols/route/Link.cpp",
"protocols/route/Route.cpp",
"protocols/route/structs.cpp",

View file

@ -51,24 +51,24 @@ static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags, protocols::M
printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED");
switch (genre) {
case protocols::MessageGenre::UNKNOWN:
case protocols::MessageGenre::Unknown:
break;
case protocols::MessageGenre::GET:
case protocols::MessageGenre::Get:
printFlag(NLM_F_DUMP, "DUMP"); // ROOT | MATCH
printFlag(NLM_F_ROOT, "ROOT");
printFlag(NLM_F_MATCH, "MATCH");
printFlag(NLM_F_ATOMIC, "ATOMIC");
break;
case protocols::MessageGenre::NEW:
case protocols::MessageGenre::New:
printFlag(NLM_F_REPLACE, "REPLACE");
printFlag(NLM_F_EXCL, "EXCL");
printFlag(NLM_F_CREATE, "CREATE");
printFlag(NLM_F_APPEND, "APPEND");
break;
case protocols::MessageGenre::DELETE:
case protocols::MessageGenre::Delete:
printFlag(NLM_F_NONREC, "NONREC");
break;
case protocols::MessageGenre::ACK:
case protocols::MessageGenre::Ack:
printFlag(NLM_F_CAPPED, "CAPPED");
printFlag(NLM_F_ACK_TLVS, "ACK_TLVS");
break;
@ -99,11 +99,25 @@ static void toStream(std::stringstream& ss, const Buffer<uint8_t> data) {
static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
const protocols::AttributeMap& attrMap) {
using DataType = protocols::AttributeDefinition::DataType;
using Flags = protocols::AttributeDefinition::Flags;
const auto attrtype = attrMap[attr->nla_type];
ss << attrtype.name << ": ";
ss << attrtype.name;
if (attrtype.dataType == DataType::Flag && attr.data<uint8_t>().getRaw().len() == 0) return;
ss << ": ";
if (attrtype.flags == Flags::Verbose) {
const auto raw = attr.data<uint8_t>();
ss << "{len=" << raw.getRaw().len();
ss << ", crc=" << std::hex << std::setw(4) << crc16(raw) << std::dec;
ss << "}";
return;
}
switch (attrtype.dataType) {
case DataType::Raw:
case DataType::Flag:
toStream(ss, attr.data<uint8_t>());
break;
case DataType::Nested: {
@ -117,13 +131,19 @@ static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
ss << '}';
break;
}
case DataType::StringNul:
case DataType::String: {
const auto str = attr.data<char>().getRaw();
ss << '"' << printableOnly({str.ptr(), str.len()}) << '"';
auto len = str.len();
if (attrtype.dataType == DataType::StringNul && len > 0 && str.ptr()[len - 1] == '\0') {
len--;
}
ss << '"' << printableOnly({str.ptr(), len}) << '"';
break;
}
case DataType::Uint:
ss << attr.data<uint32_t>().copyFirst();
ss << attr.data<uint64_t>().copyFirst();
break;
case DataType::Struct: {
const auto structToStream =
@ -147,10 +167,12 @@ std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload
}
protocols::NetlinkProtocol& protocolDescr = *protocolMaybe;
const auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
const auto msgDetails =
protocols::MessageDescriptor::getMessageDetails(msgDescMaybe, hdr->nlmsg_type);
if (msgDescMaybe.has_value()) msgDescMaybe->get().track(hdr);
ss << "nlmsg{" << protocolDescr.getName() << " ";
ss << "hdr={";

View file

@ -56,15 +56,17 @@ const AttributeMap& MessageDescriptor::getAttributeMap() const {
MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(nlmsgtype_t msgtype) const {
const auto it = mMessageDetails.find(msgtype);
if (it == mMessageDetails.end()) return {std::to_string(msgtype), MessageGenre::UNKNOWN};
if (it == mMessageDetails.end()) return {std::to_string(msgtype), MessageGenre::Unknown};
return it->second;
}
MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(
const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
const std::optional<std::reference_wrapper<MessageDescriptor>>& msgDescMaybe,
nlmsgtype_t msgtype) {
if (msgDescMaybe.has_value()) return msgDescMaybe->get().getMessageDetails(msgtype);
return {std::to_string(msgtype), protocols::MessageGenre::UNKNOWN};
return {std::to_string(msgtype), protocols::MessageGenre::Unknown};
}
void MessageDescriptor::track(const Buffer<nlmsghdr> /* hdr */) {}
} // namespace android::nl::protocols

View file

@ -54,17 +54,64 @@ class AttributeMap : private std::map<std::optional<nlattrtype_t>, AttributeDefi
*/
struct AttributeDefinition {
enum class DataType : uint8_t {
/**
* Binary blob (or attribute of unknown type).
*/
Raw,
/**
* Nested attribute (with or without NLA_F_NESTED).
*/
Nested,
/**
* Non-null terminated string.
*
* The length of the string is determined by the size of an attribute.
*/
String,
/**
* Null terminated string.
*/
StringNul,
/**
* Unsigned integer of size 8, 16, 32 or 64 bits.
*/
Uint,
/**
* Structure which printer is defined in ops ToStream variant.
*/
Struct,
/**
* Flag attribute.
*
* The attribute doesn't have any contents. The flag is set when the attribute is present,
* it's not when it's absent from attribute list.
*/
Flag,
};
enum class Flags : uint8_t {
Verbose = (1 << 0),
};
using ToStream = std::function<void(std::stringstream& ss, const Buffer<nlattr> attr)>;
std::string name;
DataType dataType = DataType::Raw;
std::variant<AttributeMap, ToStream> ops = AttributeMap{};
/**
* Attribute flags.
*
* It's not really a bitmask flag set (since you are not supposed to compare enum class by
* bitmask), but std::set<Flags> bumps compile time from 16s to 3m. Let's leave it as-is for
* now and revisit if we get some flags that can be used in pairs. When it happens, review all
* uses of the flags field to include the "&" operator and not "==".
*/
Flags flags = {};
};
/**
@ -74,11 +121,11 @@ struct AttributeDefinition {
* section in linux/netlink.h.
*/
enum class MessageGenre {
UNKNOWN,
GET,
NEW,
DELETE,
ACK,
Unknown,
Get,
New,
Delete,
Ack,
};
/**
@ -103,8 +150,15 @@ class MessageDescriptor {
MessageDetails getMessageDetails(nlmsgtype_t msgtype) const;
virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
/**
* Message tracking for stateful protocols (such as NETLINK_GENERIC).
*
* \param hdr Message to track
*/
virtual void track(const Buffer<nlmsghdr> hdr);
static MessageDetails getMessageDetails(
const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
const std::optional<std::reference_wrapper<MessageDescriptor>>& msgDescMaybe,
nlmsgtype_t msgtype);
protected:

View file

@ -32,7 +32,7 @@ const std::string& NetlinkProtocol::getName() const {
return mName;
}
const std::optional<std::reference_wrapper<const MessageDescriptor>>
const std::optional<std::reference_wrapper<MessageDescriptor>>
NetlinkProtocol::getMessageDescriptor(nlmsgtype_t nlmsg_type) {
if (mMessageDescrs.count(nlmsg_type) == 0) return std::nullopt;
return *mMessageDescrs.find(nlmsg_type)->second;
@ -41,7 +41,7 @@ NetlinkProtocol::getMessageDescriptor(nlmsgtype_t nlmsg_type) {
NetlinkProtocol::MessageDescriptorMap NetlinkProtocol::toMap(
const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
MessageDescriptorMap map;
for (const auto& descr : descrs) {
for (auto& descr : descrs) {
for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
map.emplace(mtype, descr);
}

View file

@ -40,17 +40,17 @@ class NetlinkProtocol {
const std::string& getName() const;
virtual const std::optional<std::reference_wrapper<const MessageDescriptor>>
getMessageDescriptor(nlmsgtype_t nlmsg_type);
virtual const std::optional<std::reference_wrapper<MessageDescriptor>> getMessageDescriptor(
nlmsgtype_t nlmsg_type);
protected:
typedef std::vector<std::shared_ptr<const MessageDescriptor>> MessageDescriptorList;
typedef std::vector<std::shared_ptr<MessageDescriptor>> MessageDescriptorList;
NetlinkProtocol(int protocol, const std::string& name,
const MessageDescriptorList&& messageDescrs);
private:
typedef std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> MessageDescriptorMap;
typedef std::map<nlmsgtype_t, std::shared_ptr<MessageDescriptor>> MessageDescriptorMap;
const int mProtocol;
const std::string mName;

View file

@ -20,9 +20,9 @@ namespace android::nl::protocols::base {
// clang-format off
Empty::Empty() : MessageDefinition<char>("nlmsg", {
{NLMSG_NOOP, {"NOOP", MessageGenre::UNKNOWN}},
{NLMSG_DONE, {"DONE", MessageGenre::UNKNOWN}},
{NLMSG_OVERRUN, {"OVERRUN", MessageGenre::UNKNOWN}},
{NLMSG_NOOP, {"NOOP", MessageGenre::Unknown}},
{NLMSG_DONE, {"DONE", MessageGenre::Unknown}},
{NLMSG_OVERRUN, {"OVERRUN", MessageGenre::Unknown}},
}) {}
// clang-format on

View file

@ -20,13 +20,15 @@
#include <libnl++/printer.h>
#include <map>
namespace android::nl::protocols::base {
using DataType = AttributeDefinition::DataType;
// clang-format off
Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
{NLMSG_ERROR, {"ERROR", MessageGenre::ACK}},
{NLMSG_ERROR, {"ERROR", MessageGenre::Ack}},
}, {
{NLMSGERR_ATTR_MSG, {"MSG", DataType::String}},
{NLMSGERR_ATTR_OFFS, {"OFFS", DataType::Uint}},
@ -34,9 +36,156 @@ Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
}), mProtocol(protocol) {}
// clang-format on
std::map<int, std::string> errnoNames{
{EPERM, "EPERM"}, // Operation not permitted
{ENOENT, "ENOENT"}, // No such file or directory
{ESRCH, "ESRCH"}, // No such process
{EINTR, "EINTR"}, // Interrupted system call
{EIO, "EIO"}, // I/O error
{ENXIO, "ENXIO"}, // No such device or address
{E2BIG, "E2BIG"}, // Argument list too long
{ENOEXEC, "ENOEXEC"}, // Exec format error
{EBADF, "EBADF"}, // Bad file number
{ECHILD, "ECHILD"}, // No child processes
{EAGAIN, "EAGAIN"}, // Try again
{ENOMEM, "ENOMEM"}, // Out of memory
{EACCES, "EACCES"}, // Permission denied
{EFAULT, "EFAULT"}, // Bad address
{ENOTBLK, "ENOTBLK"}, // Block device required
{EBUSY, "EBUSY"}, // Device or resource busy
{EEXIST, "EEXIST"}, // File exists
{EXDEV, "EXDEV"}, // Cross-device link
{ENODEV, "ENODEV"}, // No such device
{ENOTDIR, "ENOTDIR"}, // Not a directory
{EISDIR, "EISDIR"}, // Is a directory
{EINVAL, "EINVAL"}, // Invalid argument
{ENFILE, "ENFILE"}, // File table overflow
{EMFILE, "EMFILE"}, // Too many open files
{ENOTTY, "ENOTTY"}, // Not a typewriter
{ETXTBSY, "ETXTBSY"}, // Text file busy
{EFBIG, "EFBIG"}, // File too large
{ENOSPC, "ENOSPC"}, // No space left on device
{ESPIPE, "ESPIPE"}, // Illegal seek
{EROFS, "EROFS"}, // Read-only file system
{EMLINK, "EMLINK"}, // Too many links
{EPIPE, "EPIPE"}, // Broken pipe
{EDOM, "EDOM"}, // Math argument out of domain of func
{ERANGE, "ERANGE"}, // Math result not representable
{EDEADLK, "EDEADLK"}, // Resource deadlock would occur
{ENAMETOOLONG, "ENAMETOOLONG"}, // File name too long
{ENOLCK, "ENOLCK"}, // No record locks available
{ENOSYS, "ENOSYS"}, // Invalid system call number
{ENOTEMPTY, "ENOTEMPTY"}, // Directory not empty
{ELOOP, "ELOOP"}, // Too many symbolic links encountered
{ENOMSG, "ENOMSG"}, // No message of desired type
{EIDRM, "EIDRM"}, // Identifier removed
{ECHRNG, "ECHRNG"}, // Channel number out of range
{EL2NSYNC, "EL2NSYNC"}, // Level 2 not synchronized
{EL3HLT, "EL3HLT"}, // Level 3 halted
{EL3RST, "EL3RST"}, // Level 3 reset
{ELNRNG, "ELNRNG"}, // Link number out of range
{EUNATCH, "EUNATCH"}, // Protocol driver not attached
{ENOCSI, "ENOCSI"}, // No CSI structure available
{EL2HLT, "EL2HLT"}, // Level 2 halted
{EBADE, "EBADE"}, // Invalid exchange
{EBADR, "EBADR"}, // Invalid request descriptor
{EXFULL, "EXFULL"}, // Exchange full
{ENOANO, "ENOANO"}, // No anode
{EBADRQC, "EBADRQC"}, // Invalid request code
{EBADSLT, "EBADSLT"}, // Invalid slot
{EBFONT, "EBFONT"}, // Bad font file format
{ENOSTR, "ENOSTR"}, // Device not a stream
{ENODATA, "ENODATA"}, // No data available
{ETIME, "ETIME"}, // Timer expired
{ENOSR, "ENOSR"}, // Out of streams resources
{ENONET, "ENONET"}, // Machine is not on the network
{ENOPKG, "ENOPKG"}, // Package not installed
{EREMOTE, "EREMOTE"}, // Object is remote
{ENOLINK, "ENOLINK"}, // Link has been severed
{EADV, "EADV"}, // Advertise error
{ESRMNT, "ESRMNT"}, // Srmount error
{ECOMM, "ECOMM"}, // Communication error on send
{EPROTO, "EPROTO"}, // Protocol error
{EMULTIHOP, "EMULTIHOP"}, // Multihop attempted
{EDOTDOT, "EDOTDOT"}, // RFS specific error
{EBADMSG, "EBADMSG"}, // Not a data message
{EOVERFLOW, "EOVERFLOW"}, // Value too large for defined data type
{ENOTUNIQ, "ENOTUNIQ"}, // Name not unique on network
{EBADFD, "EBADFD"}, // File descriptor in bad state
{EREMCHG, "EREMCHG"}, // Remote address changed
{ELIBACC, "ELIBACC"}, // Can not access a needed shared library
{ELIBBAD, "ELIBBAD"}, // Accessing a corrupted shared library
{ELIBSCN, "ELIBSCN"}, // .lib section in a.out corrupted
{ELIBMAX, "ELIBMAX"}, // Attempting to link in too many shared libraries
{ELIBEXEC, "ELIBEXEC"}, // Cannot exec a shared library directly
{EILSEQ, "EILSEQ"}, // Illegal byte sequence
{ERESTART, "ERESTART"}, // Interrupted system call should be restarted
{ESTRPIPE, "ESTRPIPE"}, // Streams pipe error
{EUSERS, "EUSERS"}, // Too many users
{ENOTSOCK, "ENOTSOCK"}, // Socket operation on non-socket
{EDESTADDRREQ, "EDESTADDRREQ"}, // Destination address required
{EMSGSIZE, "EMSGSIZE"}, // Message too long
{EPROTOTYPE, "EPROTOTYPE"}, // Protocol wrong type for socket
{ENOPROTOOPT, "ENOPROTOOPT"}, // Protocol not available
{EPROTONOSUPPORT, "EPROTONOSUPPORT"}, // Protocol not supported
{ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT"}, // Socket type not supported
{EOPNOTSUPP, "EOPNOTSUPP"}, // Operation not supported on transport endpoint
{EPFNOSUPPORT, "EPFNOSUPPORT"}, // Protocol family not supported
{EAFNOSUPPORT, "EAFNOSUPPORT"}, // Address family not supported by protocol
{EADDRINUSE, "EADDRINUSE"}, // Address already in use
{EADDRNOTAVAIL, "EADDRNOTAVAIL"}, // Cannot assign requested address
{ENETDOWN, "ENETDOWN"}, // Network is down
{ENETUNREACH, "ENETUNREACH"}, // Network is unreachable
{ENETRESET, "ENETRESET"}, // Network dropped connection because of reset
{ECONNABORTED, "ECONNABORTED"}, // Software caused connection abort
{ECONNRESET, "ECONNRESET"}, // Connection reset by peer
{ENOBUFS, "ENOBUFS"}, // No buffer space available
{EISCONN, "EISCONN"}, // Transport endpoint is already connected
{ENOTCONN, "ENOTCONN"}, // Transport endpoint is not connected
{ESHUTDOWN, "ESHUTDOWN"}, // Cannot send after transport endpoint shutdown
{ETOOMANYREFS, "ETOOMANYREFS"}, // Too many references: cannot splice
{ETIMEDOUT, "ETIMEDOUT"}, // Connection timed out
{ECONNREFUSED, "ECONNREFUSED"}, // Connection refused
{EHOSTDOWN, "EHOSTDOWN"}, // Host is down
{EHOSTUNREACH, "EHOSTUNREACH"}, // No route to host
{EALREADY, "EALREADY"}, // Operation already in progress
{EINPROGRESS, "EINPROGRESS"}, // Operation now in progress
{ESTALE, "ESTALE"}, // Stale file handle
{EUCLEAN, "EUCLEAN"}, // Structure needs cleaning
{ENOTNAM, "ENOTNAM"}, // Not a XENIX named type file
{ENAVAIL, "ENAVAIL"}, // No XENIX semaphores available
{EISNAM, "EISNAM"}, // Is a named type file
{EREMOTEIO, "EREMOTEIO"}, // Remote I/O error
{EDQUOT, "EDQUOT"}, // Quota exceeded
{ENOMEDIUM, "ENOMEDIUM"}, // No medium found
{EMEDIUMTYPE, "EMEDIUMTYPE"}, // Wrong medium type
{ECANCELED, "ECANCELED"}, // Operation Canceled
{ENOKEY, "ENOKEY"}, // Required key not available
{EKEYEXPIRED, "EKEYEXPIRED"}, // Key has expired
{EKEYREVOKED, "EKEYREVOKED"}, // Key has been revoked
{EKEYREJECTED, "EKEYREJECTED"}, // Key was rejected by service
{EOWNERDEAD, "EOWNERDEAD"}, // Owner died
{ENOTRECOVERABLE, "ENOTRECOVERABLE"}, // State not recoverable
{ERFKILL, "ERFKILL"}, // Operation not possible due to RF-kill
{EHWPOISON, "EHWPOISON"}, // Memory page has hardware error
// Duplicates: EWOULDBLOCK (Operation would block), EDEADLOCK
};
void Error::toStream(std::stringstream& ss, const nlmsgerr& data) const {
ss << "nlmsgerr{error=" << data.error
<< ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
ss << "nlmsgerr{";
if (data.error == 0) {
ss << "ACK";
} else {
ss << "error=";
const auto nameIt = errnoNames.find(-data.error);
if (nameIt == errnoNames.end()) {
ss << data.error;
} else {
ss << nameIt->second;
}
}
ss << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
}
} // namespace android::nl::protocols::base

View file

@ -16,12 +16,19 @@
#include "Ctrl.h"
#include "families/Nl80211.h"
#include <libnl++/Message.h>
namespace android::nl::protocols::generic {
using DataType = AttributeDefinition::DataType;
using Flags = AttributeDefinition::Flags;
// clang-format off
Ctrl::Ctrl() : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL", {
Ctrl::Ctrl(Generic::FamilyRegister& familyRegister)
: GenericMessageBase(GENL_ID_CTRL, "ID_CTRL",
{
{CTRL_CMD_NEWFAMILY, "NEWFAMILY"},
{CTRL_CMD_DELFAMILY, "DELFAMILY"},
{CTRL_CMD_GETFAMILY, "GETFAMILY"},
@ -33,7 +40,7 @@ Ctrl::Ctrl() : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL", {
{CTRL_CMD_GETMCAST_GRP, "GETMCAST_GRP"},
}, {
{CTRL_ATTR_FAMILY_ID, {"FAMILY_ID", DataType::Uint}},
{CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::String}},
{CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::StringNul}},
{CTRL_ATTR_VERSION, {"VERSION", DataType::Uint}},
{CTRL_ATTR_HDRSIZE, {"HDRSIZE", DataType::Uint}},
{CTRL_ATTR_MAXATTR, {"MAXATTR", DataType::Uint}},
@ -42,14 +49,31 @@ Ctrl::Ctrl() : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL", {
{CTRL_ATTR_OP_ID, {"ID", DataType::Uint}},
{CTRL_ATTR_OP_FLAGS, {"FLAGS", DataType::Uint}},
}}},
}}},
}, Flags::Verbose}},
{CTRL_ATTR_MCAST_GROUPS, {"MCAST_GROUPS", DataType::Nested, AttributeMap{
{std::nullopt, {"GRP", DataType::Nested, AttributeMap{
{CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::String}},
{CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::StringNul}},
{CTRL_ATTR_MCAST_GRP_ID, {"ID", DataType::Uint}},
}}},
}}},
}) {}
}), mFamilyRegister(familyRegister) {}
// clang-format on
void Ctrl::track(const Buffer<nlmsghdr> hdr) {
const auto msgMaybe = Message<genlmsghdr>::parse(hdr, {GENL_ID_CTRL});
if (!msgMaybe.has_value()) return;
const auto msg = *msgMaybe;
if (msg->cmd != CTRL_CMD_NEWFAMILY) return;
const auto familyId = msg.attributes.get<uint16_t>(CTRL_ATTR_FAMILY_ID);
const auto familyName = msg.attributes.get<std::string>(CTRL_ATTR_FAMILY_NAME);
/* For now, we support just a single family. But if you add more, please define proper
* abstraction and not hardcode every name and class here.
*/
if (familyName == "nl80211") {
mFamilyRegister[familyId] = std::make_shared<families::Nl80211>(familyId);
}
}
} // namespace android::nl::protocols::generic

View file

@ -16,13 +16,19 @@
#pragma once
#include "Generic.h"
#include "GenericMessageBase.h"
namespace android::nl::protocols::generic {
class Ctrl : public GenericMessageBase {
public:
Ctrl();
Ctrl(Generic::FamilyRegister& familyRegister);
void track(const Buffer<nlmsghdr> hdr) override;
private:
Generic::FamilyRegister& mFamilyRegister;
};
} // namespace android::nl::protocols::generic

View file

@ -21,11 +21,12 @@
namespace android::nl::protocols::generic {
Generic::Generic() : NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>()}) {}
Generic::Generic()
: NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>(mFamilyRegister)}) {}
const std::optional<std::reference_wrapper<const MessageDescriptor>> Generic::getMessageDescriptor(
const std::optional<std::reference_wrapper<MessageDescriptor>> Generic::getMessageDescriptor(
nlmsgtype_t nlmsg_type) {
const auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
if (desc.has_value()) return desc;
auto it = mFamilyRegister.find(nlmsg_type);

View file

@ -25,13 +25,15 @@ namespace android::nl::protocols::generic {
*/
class Generic : public NetlinkProtocol {
public:
typedef std::map<nlmsgtype_t, std::shared_ptr<MessageDescriptor>> FamilyRegister;
Generic();
const std::optional<std::reference_wrapper<const MessageDescriptor>> getMessageDescriptor(
const std::optional<std::reference_wrapper<MessageDescriptor>> getMessageDescriptor(
nlmsgtype_t nlmsg_type);
private:
std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> mFamilyRegister;
FamilyRegister mFamilyRegister;
};
} // namespace android::nl::protocols::generic

View file

@ -22,16 +22,27 @@ GenericMessageBase::GenericMessageBase(
nlmsgtype_t msgtype, const std::string&& msgname,
const std::initializer_list<GenericCommandNameMap::value_type> commandNames,
const std::initializer_list<AttributeMap::value_type> attrTypes)
: MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::UNKNOWN}}},
: MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::Unknown}}},
attrTypes),
mCommandNames(commandNames) {}
void GenericMessageBase::toStream(std::stringstream& ss, const genlmsghdr& data) const {
const auto commandNameIt = mCommandNames.find(data.cmd);
const auto commandName = (commandNameIt == mCommandNames.end())
? std::nullopt
: std::optional<std::string>(commandNameIt->second);
if (commandName.has_value() && data.version == 1 && data.reserved == 0) {
// short version
ss << *commandName;
return;
}
ss << "genlmsghdr{";
if (mCommandNames.count(data.cmd) == 0) {
if (commandName.has_value()) {
ss << "cmd=" << unsigned(data.cmd);
} else {
ss << "cmd=" << mCommandNames.find(data.cmd)->second;
ss << "cmd=" << *commandName;
}
ss << ", version=" << unsigned(data.version);
if (data.reserved != 0) ss << ", reserved=" << data.reserved;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,28 @@
/*
* 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.
*/
#pragma once
#include "../GenericMessageBase.h"
namespace android::nl::protocols::generic::families {
class Nl80211 : public GenericMessageBase {
public:
Nl80211(nlmsgtype_t familyId);
};
} // namespace android::nl::protocols::generic::families

View file

@ -16,6 +16,7 @@
#include "Link.h"
#include "../structs.h"
#include "structs.h"
#include <net/if.h>
@ -26,9 +27,9 @@ using DataType = AttributeDefinition::DataType;
// clang-format off
Link::Link() : MessageDefinition<ifinfomsg>("link", {
{RTM_NEWLINK, {"NEWLINK", MessageGenre::NEW}},
{RTM_DELLINK, {"DELLINK", MessageGenre::DELETE}},
{RTM_GETLINK, {"GETLINK", MessageGenre::GET}},
{RTM_NEWLINK, {"NEWLINK", MessageGenre::New}},
{RTM_DELLINK, {"DELLINK", MessageGenre::Delete}},
{RTM_GETLINK, {"GETLINK", MessageGenre::Get}},
}, {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},

View file

@ -30,16 +30,6 @@ void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr);
// ifla_cacheinfo
void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr);
template <typename T>
void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
ss << '{';
for (const auto it : attr.data<T>().getRaw()) {
ss << it << ',';
}
ss.seekp(-1, std::ios_base::cur);
ss << '}';
}
// rtnl_link_stats or rtnl_link_stats64
template <typename T>
void statsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {

View file

@ -0,0 +1,33 @@
/*
* 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.
*/
#pragma once
#include <sstream>
namespace android::nl::protocols {
template <typename T>
void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
ss << '{';
for (const auto it : attr.data<T>().getRaw()) {
ss << it << ',';
}
ss.seekp(-1, std::ios_base::cur);
ss << '}';
}
} // namespace android::nl::protocols