Merge changes I8fe05731,Ib71c9288,Ib629cad3
* changes:
Trim trailing NIL character when fetching string attribute
Implement message kinds for flag printing
Refactor MessageFactory
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index 5a1105c..083f4f0 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -34,7 +34,7 @@
static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
base::unique_fd socket(const std::string& ifname) {
- struct sockaddr_can addr = {};
+ sockaddr_can addr = {};
addr.can_family = AF_CAN;
addr.can_ifindex = nametoindex(ifname);
if (addr.can_ifindex == 0) {
@@ -58,7 +58,7 @@
return {};
}
- if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
+ if (0 != bind(sock.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
LOG(ERROR) << "Can't bind to CAN interface " << ifname;
return {};
}
@@ -67,26 +67,25 @@
}
bool setBitrate(std::string ifname, uint32_t bitrate) {
- struct can_bittiming bt = {};
+ can_bittiming bt = {};
bt.bitrate = bitrate;
- nl::MessageFactory<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
- const auto ifidx = nametoindex(ifname);
- if (ifidx == 0) {
+ req->ifi_index = nametoindex(ifname);
+ if (req->ifi_index == 0) {
LOG(ERROR) << "Can't find interface " << ifname;
return false;
}
- req.data().ifi_index = ifidx;
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, "can");
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, "can");
{
- auto infodata = req.nest(IFLA_INFO_DATA);
+ auto infodata = req.addNested(IFLA_INFO_DATA);
/* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
* and IFLA_CAN_CTRLMODE as well. */
- req.addattr(IFLA_CAN_BITTIMING, bt);
+ req.add(IFLA_CAN_BITTIMING, bt);
}
}
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index e2ba2cb..9447c0c 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -62,13 +62,13 @@
}
bool add(std::string dev, std::string type) {
- nl::MessageFactory<struct ifinfomsg> req(RTM_NEWLINK,
- NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
- req.addattr(IFLA_IFNAME, dev);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+ req.add(IFLA_IFNAME, dev);
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, type);
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, type);
}
nl::Socket sock(NETLINK_ROUTE);
@@ -76,8 +76,8 @@
}
bool del(std::string dev) {
- nl::MessageFactory<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
- req.addattr(IFLA_IFNAME, dev);
+ nl::MessageFactory<ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
+ req.add(IFLA_IFNAME, dev);
nl::Socket sock(NETLINK_ROUTE);
return sock.send(req) && sock.receiveAck(req);
diff --git a/automotive/can/1.0/default/libnetdevice/vlan.cpp b/automotive/can/1.0/default/libnetdevice/vlan.cpp
index 33dc029..ee02f7b 100644
--- a/automotive/can/1.0/default/libnetdevice/vlan.cpp
+++ b/automotive/can/1.0/default/libnetdevice/vlan.cpp
@@ -33,18 +33,18 @@
return false;
}
- nl::MessageFactory<struct ifinfomsg> req(RTM_NEWLINK,
- NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
- req.addattr(IFLA_IFNAME, vlan);
- req.addattr<uint32_t>(IFLA_LINK, ethidx);
+ nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+ NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+ req.add(IFLA_IFNAME, vlan);
+ req.add<uint32_t>(IFLA_LINK, ethidx);
{
- auto linkinfo = req.nest(IFLA_LINKINFO);
- req.addattr(IFLA_INFO_KIND, "vlan");
+ auto linkinfo = req.addNested(IFLA_LINKINFO);
+ req.add(IFLA_INFO_KIND, "vlan");
{
- auto linkinfo = req.nest(IFLA_INFO_DATA);
- req.addattr(IFLA_VLAN_ID, id);
+ auto linkinfo = req.addNested(IFLA_INFO_DATA);
+ req.add(IFLA_VLAN_ID, id);
}
}
diff --git a/automotive/can/1.0/default/libnl++/Attributes.cpp b/automotive/can/1.0/default/libnl++/Attributes.cpp
index c101647..620f57b 100644
--- a/automotive/can/1.0/default/libnl++/Attributes.cpp
+++ b/automotive/can/1.0/default/libnl++/Attributes.cpp
@@ -49,7 +49,11 @@
template <>
std::string Attributes::parse(Buffer<nlattr> buf) {
const auto rawString = buf.data<char>().getRaw();
- return std::string(rawString.ptr(), rawString.len());
+ std::string str(rawString.ptr(), rawString.len());
+
+ str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
+
+ return str;
}
template <typename T>
diff --git a/automotive/can/1.0/default/libnl++/MessageFactory.cpp b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
index 0c6a331..6f35897 100644
--- a/automotive/can/1.0/default/libnl++/MessageFactory.cpp
+++ b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
@@ -17,41 +17,36 @@
#include <libnl++/MessageFactory.h>
#include <android-base/logging.h>
+#include <libnl++/bits.h>
-// for RTA_ macros missing from NLA_ definitions
-#include <linux/rtnetlink.h>
+namespace android::nl {
-namespace android::nl::impl {
-
-static struct nlattr* nlmsg_tail(struct nlmsghdr* n) {
- return reinterpret_cast<struct nlattr*>( //
- reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
+static nlattr* tail(nlmsghdr* msg) {
+ return reinterpret_cast<nlattr*>(uintptr_t(msg) + impl::align(msg->nlmsg_len));
}
-struct nlattr* addattr_l(struct nlmsghdr* n, size_t maxLen, nlattrtype_t type, const void* data,
- size_t dataLen) {
- size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
+nlattr* MessageFactoryBase::add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+ size_t dataLen) {
+ const auto totalAttrLen = impl::space<nlattr>(dataLen);
+ const auto newLen = impl::align(msg->nlmsg_len) + totalAttrLen;
if (newLen > maxLen) {
- LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
+ LOG(ERROR) << "Can't add attribute of size " << dataLen //
+ << " - exceeded maxLen: " << newLen << " > " << maxLen;
return nullptr;
}
- auto attr = nlmsg_tail(n);
- attr->nla_len = RTA_SPACE(dataLen);
+ auto attr = tail(msg);
+ attr->nla_len = totalAttrLen;
attr->nla_type = type;
- if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
+ if (dataLen > 0) memcpy(impl::data<nlattr, void>(attr), data, dataLen);
- n->nlmsg_len = newLen;
+ msg->nlmsg_len = newLen;
return attr;
}
-struct nlattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, nlattrtype_t type) {
- return addattr_l(n, maxLen, type, nullptr, 0);
+void MessageFactoryBase::closeNested(nlmsghdr* msg, nlattr* nested) {
+ if (nested == nullptr) return;
+ nested->nla_len = uintptr_t(tail(msg)) - uintptr_t(nested);
}
-void addattr_nest_end(struct nlmsghdr* n, struct nlattr* nest) {
- size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
- nest->nla_len = nestLen;
-}
-
-} // namespace android::nl::impl
+} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/Socket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
index 1a34df8..9e96ea9 100644
--- a/automotive/can/1.0/default/libnl++/Socket.cpp
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -49,8 +49,8 @@
bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
if constexpr (kSuperVerbose) {
- LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending Netlink message (" //
- << msg->nlmsg_pid << " -> " << sa.nl_pid << "): " << toString(msg, mProtocol);
+ LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending to " << sa.nl_pid << ": "
+ << toString(msg, mProtocol);
}
if (mFailed) return false;
@@ -97,8 +97,7 @@
Buffer<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(mReceiveBuffer.data()), bytesReceived);
if constexpr (kSuperVerbose) {
- LOG(VERBOSE) << "received (" << sa.nl_pid << " -> " << msg->nlmsg_pid << "):" //
- << toString(msg, mProtocol);
+ LOG(VERBOSE) << "received from " << sa.nl_pid << ": " << toString(msg, mProtocol);
}
return {msg, sa};
}
diff --git a/automotive/can/1.0/default/libnl++/common.cpp b/automotive/can/1.0/default/libnl++/common.cpp
index 74eee24..23c2d94 100644
--- a/automotive/can/1.0/default/libnl++/common.cpp
+++ b/automotive/can/1.0/default/libnl++/common.cpp
@@ -32,9 +32,7 @@
return 0;
}
-std::string sanitize(std::string str) {
- str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
-
+std::string printableOnly(std::string str) {
const auto isInvalid = [](char c) { return !isprint(c); };
std::replace_if(str.begin(), str.end(), isInvalid, '?');
diff --git a/automotive/can/1.0/default/libnl++/common.h b/automotive/can/1.0/default/libnl++/common.h
index 1d9dbab..38263c5 100644
--- a/automotive/can/1.0/default/libnl++/common.h
+++ b/automotive/can/1.0/default/libnl++/common.h
@@ -37,11 +37,14 @@
unsigned int nametoindex(const std::string& ifname);
/**
- * Sanitize a string of unknown contents.
+ * Filter a string against non-printable characters.
*
- * Trims the string to the first '\0' character and replaces all non-printable characters with '?'.
+ * Replaces all non-printable characters with '?'.
+ *
+ * \param str String to filter.
+ * \return Filtered string.
*/
-std::string sanitize(std::string str);
+std::string printableOnly(std::string str);
/**
* Calculates a (optionally running) CRC16 checksum.
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
index a6f8f7a..c3137c8 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/logging.h>
+#include <libnl++/bits.h>
#include <linux/netlink.h>
@@ -25,7 +26,7 @@
namespace android::nl {
/**
- * Buffer wrapper containing netlink structure (e.g. struct nlmsghdr, struct nlattr).
+ * Buffer wrapper containing netlink structure (e.g. nlmsghdr, nlattr).
*
* This is a C++-style, memory safe(r) and generic implementation of linux/netlink.h macros.
*
@@ -43,15 +44,6 @@
*/
template <typename T>
class Buffer {
- // The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h
-
- static constexpr size_t alignto = NLMSG_ALIGNTO;
- static_assert(NLMSG_ALIGNTO == NLA_ALIGNTO);
-
- static constexpr size_t align(size_t ptr) { return (ptr + alignto - 1) & ~(alignto - 1); }
-
- static constexpr size_t hdrlen = align(sizeof(T));
-
public:
/**
* Constructs empty buffer of size 0.
@@ -96,9 +88,7 @@
template <typename D>
const Buffer<D> data(size_t offset = 0) const {
- // Equivalent to NLMSG_DATA(hdr) + NLMSG_ALIGN(offset)
- const D* dptr = reinterpret_cast<const D*>(uintptr_t(mData) + hdrlen + align(offset));
- return {dptr, dataEnd()};
+ return {impl::data<const T, const D>(mData, offset), dataEnd()};
}
class iterator {
@@ -111,7 +101,7 @@
iterator operator++() {
// mBufferEnd stays the same
mCurrent.mData = reinterpret_cast<const T*>( //
- uintptr_t(mCurrent.mData) + align(mCurrent.declaredLength()));
+ uintptr_t(mCurrent.mData) + impl::align(mCurrent.declaredLength()));
return *this;
}
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
index 5272577..c3d72c5 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
@@ -17,6 +17,7 @@
#pragma once
#include <android-base/macros.h>
+#include <libnl++/Buffer.h>
#include <libnl++/types.h>
#include <linux/netlink.h>
@@ -25,131 +26,140 @@
namespace android::nl {
-/** Implementation details, do not use outside MessageFactory template. */
-namespace impl {
-
-struct nlattr* addattr_l(struct nlmsghdr* n, size_t maxLen, nlattrtype_t type, const void* data,
- size_t dataLen);
-struct nlattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, nlattrtype_t type);
-void addattr_nest_end(struct nlmsghdr* n, struct nlattr* nest);
-
-} // namespace impl
+class MessageFactoryBase {
+ protected:
+ static nlattr* add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+ size_t dataLen);
+ static void closeNested(nlmsghdr* msg, nlattr* nested);
+};
/**
* Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
*
- * \param T specific message header (such as struct ifinfomsg)
- * \param BUFSIZE how much space to reserve for payload (not counting the header size)
+ * \param T Message payload type (such as ifinfomsg).
+ * \param BUFSIZE how much space to reserve for attributes.
*/
template <class T, unsigned int BUFSIZE = 128>
-struct MessageFactory {
- struct RequestData {
- struct nlmsghdr nlmsg;
+class MessageFactory : private MessageFactoryBase {
+ struct alignas(NLMSG_ALIGNTO) Message {
+ nlmsghdr header;
T data;
- char buf[BUFSIZE];
+ uint8_t attributesBuffer[BUFSIZE];
};
- static constexpr size_t totalLength = sizeof(RequestData);
-
+ public:
/**
* Create empty message.
*
- * \param type Message type (such as RTM_NEWLINK)
- * \param flags Message flags (such as NLM_F_REQUEST)
+ * \param type Message type (such as RTM_NEWLINK).
+ * \param flags Message flags (such as NLM_F_REQUEST).
*/
- MessageFactory(nlmsgtype_t type, uint16_t flags) {
- mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
- mRequest.nlmsg.nlmsg_type = type;
- mRequest.nlmsg.nlmsg_flags = flags;
+ MessageFactory(nlmsgtype_t type, uint16_t flags)
+ : header(mMessage.header), data(mMessage.data) {
+ mMessage.header.nlmsg_len = offsetof(Message, attributesBuffer);
+ mMessage.header.nlmsg_type = type;
+ mMessage.header.nlmsg_flags = flags;
}
- /** \return pointer to raw netlink message header. */
- struct nlmsghdr* header() {
- return &mRequest.nlmsg;
- }
- /** Reference to message-specific header. */
- T& data() { return mRequest.data; }
-
/**
- * Adds an attribute of a simple type.
+ * Netlink message header.
*
- * If this method fails (i.e. due to insufficient space), the message will be marked
- * as bad (\see isGood).
+ * This is a generic Netlink header containing information such as message flags.
+ */
+ nlmsghdr& header;
+
+ /**
+ * Netlink message data.
+ *
+ * This is a payload specific to a given message type.
+ */
+ T& data;
+
+ T* operator->() { return &mMessage.data; }
+
+ /**
+ * Build netlink message.
+ *
+ * In fact, this operation is almost a no-op, since the factory builds the message in a single
+ * buffer, using native data structures.
+ *
+ * A likely failure case is when the BUFSIZE template parameter is too small to acommodate
+ * added attributes. In such a case, please increase this parameter.
+ *
+ * \return Netlink message or std::nullopt in case of failure.
+ */
+ std::optional<Buffer<nlmsghdr>> build() const {
+ if (!mIsGood) return std::nullopt;
+ return {{&mMessage.header, mMessage.header.nlmsg_len}};
+ }
+
+ /**
+ * Adds an attribute of a trivially copyable type.
+ *
+ * Template specializations may extend this function for other types, such as std::string.
+ *
+ * If this method fails (i.e. due to insufficient space), a warning will be printed to the log
+ * and the message will be marked as bad, causing later \see build call to fail.
*
* \param type attribute type (such as IFLA_IFNAME)
* \param attr attribute data
*/
template <class A>
- void addattr(nlattrtype_t type, const A& attr) {
- if (!mIsGood) return;
- auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
- if (ap == nullptr) mIsGood = false;
+ void add(nlattrtype_t type, const A& attr) {
+ add(type, &attr, sizeof(attr));
}
template <>
- void addattr(nlattrtype_t type, const std::string& s) {
- if (!mIsGood) return;
- auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
- if (ap == nullptr) mIsGood = false;
+ void add(nlattrtype_t type, const std::string& s) {
+ add(type, s.c_str(), s.size() + 1);
}
- /** Guard class to frame nested attributes. See nest(int). */
- struct Nest {
- Nest(MessageFactory& req, nlattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
- ~Nest() { mReq.nestEnd(mAttr); }
+ /** Guard class to frame nested attributes. \see addNested(nlattrtype_t). */
+ class [[nodiscard]] NestedGuard {
+ public:
+ NestedGuard(MessageFactory & req, nlattrtype_t type) : mReq(req), mAttr(req.add(type)) {}
+ ~NestedGuard() { closeNested(&mReq.mMessage.header, mAttr); }
private:
MessageFactory& mReq;
- struct nlattr* mAttr;
+ nlattr* mAttr;
- DISALLOW_COPY_AND_ASSIGN(Nest);
+ DISALLOW_COPY_AND_ASSIGN(NestedGuard);
};
/**
* Add nested attribute.
*
* The returned object is a guard for auto-nesting children inside the argument attribute.
- * When the Nest object goes out of scope, the nesting attribute is closed.
+ * When the guard object goes out of scope, the nesting attribute is closed.
*
* Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
* inside IFLA_LINKINFO:
- * MessageFactory<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+ * MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
* {
- * auto linkinfo = req.nest(IFLA_LINKINFO);
- * req.addattr(IFLA_INFO_KIND, "can");
+ * auto linkinfo = req.addNested(IFLA_LINKINFO);
+ * req.add(IFLA_INFO_KIND, "can");
* {
- * auto infodata = req.nest(IFLA_INFO_DATA);
- * req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
+ * auto infodata = req.addNested(IFLA_INFO_DATA);
+ * req.add(IFLA_CAN_BITTIMING, bitTimingStruct);
* }
* }
* // use req
*
* \param type attribute type (such as IFLA_LINKINFO)
*/
- Nest nest(int type) { return Nest(*this, type); }
-
- /**
- * Indicates, whether the message is in a good state.
- *
- * The bad state is usually a result of payload buffer being too small.
- * You can modify BUFSIZE template parameter to fix this.
- */
- bool isGood() const { return mIsGood; }
+ NestedGuard addNested(nlattrtype_t type) { return {*this, type}; }
private:
+ Message mMessage = {};
bool mIsGood = true;
- RequestData mRequest = {};
- struct nlattr* nestStart(nlattrtype_t type) {
+ nlattr* add(nlattrtype_t type, const void* data = nullptr, size_t len = 0) {
if (!mIsGood) return nullptr;
- auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
+ auto attr = MessageFactoryBase::add(&mMessage.header, sizeof(mMessage), type, data, len);
if (attr == nullptr) mIsGood = false;
return attr;
}
-
- void nestEnd(struct nlattr* nest) {
- if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
- }
};
} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
index 16b63f5..6a4e82e 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
@@ -76,13 +76,12 @@
*/
template <typename T, unsigned BUFSIZE>
bool send(MessageFactory<T, BUFSIZE>& req, const sockaddr_nl& sa) {
- if (!req.isGood()) return false;
+ req.header.nlmsg_seq = mSeq + 1;
- const auto nlmsg = req.header();
- nlmsg->nlmsg_seq = mSeq + 1;
+ const auto msg = req.build();
+ if (!msg.has_value()) return false;
- // With MessageFactory<>, we trust nlmsg_len to be correct.
- return send({nlmsg, nlmsg->nlmsg_len}, sa);
+ return send(*msg, sa);
}
/**
@@ -156,7 +155,7 @@
*/
template <typename T, unsigned BUFSIZE>
bool receiveAck(MessageFactory<T, BUFSIZE>& req) {
- return receiveAck(req.header()->nlmsg_seq);
+ return receiveAck(req.header.nlmsg_seq);
}
/**
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/bits.h b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
new file mode 100644
index 0000000..4c8f1aa
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
@@ -0,0 +1,54 @@
+/*
+ * 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 <linux/netlink.h>
+
+namespace android::nl::impl {
+
+// The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h.
+
+/**
+ * Equivalent to NLMSG_ALIGNTO.
+ */
+constexpr size_t alignto = NLMSG_ALIGNTO;
+static_assert(NLMSG_ALIGNTO == NLA_ALIGNTO);
+
+/**
+ * Equivalent to NLMSG_ALIGN(len).
+ */
+constexpr size_t align(size_t len) {
+ return (len + alignto - 1) & ~(alignto - 1);
+}
+
+/**
+ * Equivalent to NLMSG_SPACE(len).
+ */
+template <typename H>
+constexpr size_t space(size_t len) {
+ return align(align(sizeof(H)) + len);
+}
+
+/**
+ * Equivalent to NLMSG_DATA(hdr) + NLMSG_ALIGN(offset).
+ */
+template <typename H, typename D>
+constexpr D* data(H* header, size_t offset = 0) {
+ return reinterpret_cast<D*>(uintptr_t(header) + space<H>(offset));
+}
+
+} // namespace android::nl::impl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/printer.h b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
index 53a06d8..3570918 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
@@ -32,6 +32,6 @@
* \param printPayload True will stringify message data, false will only stringify the header(s).
* \return Stringified message.
*/
-std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload = false);
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload = true);
} // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/printer.cpp b/automotive/can/1.0/default/libnl++/printer.cpp
index 9735db1..e6cada2 100644
--- a/automotive/can/1.0/default/libnl++/printer.cpp
+++ b/automotive/can/1.0/default/libnl++/printer.cpp
@@ -28,10 +28,10 @@
namespace android::nl {
-static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags) {
+static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags, protocols::MessageGenre genre) {
bool first = true;
auto printFlag = [&ss, &first, &nlmsg_flags](__u16 flag, const std::string& name) {
- if (!(nlmsg_flags & flag)) return;
+ if ((nlmsg_flags & flag) != flag) return;
nlmsg_flags &= ~flag;
if (first) {
@@ -42,6 +42,7 @@
ss << name;
};
+
printFlag(NLM_F_REQUEST, "REQUEST");
printFlag(NLM_F_MULTI, "MULTI");
printFlag(NLM_F_ACK, "ACK");
@@ -49,11 +50,29 @@
printFlag(NLM_F_DUMP_INTR, "DUMP_INTR");
printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED");
- // TODO(twasilczyk): print flags depending on request type
- printFlag(NLM_F_ROOT, "ROOT-REPLACE");
- printFlag(NLM_F_MATCH, "MATCH-EXCL");
- printFlag(NLM_F_ATOMIC, "ATOMIC-CREATE");
- printFlag(NLM_F_APPEND, "APPEND");
+ switch (genre) {
+ case protocols::MessageGenre::UNKNOWN:
+ break;
+ 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:
+ 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:
+ printFlag(NLM_F_NONREC, "NONREC");
+ break;
+ case protocols::MessageGenre::ACK:
+ printFlag(NLM_F_CAPPED, "CAPPED");
+ printFlag(NLM_F_ACK_TLVS, "ACK_TLVS");
+ break;
+ }
if (nlmsg_flags != 0) {
if (!first) ss << '|';
@@ -100,7 +119,7 @@
}
case DataType::String: {
const auto str = attr.data<char>().getRaw();
- ss << '"' << sanitize({str.ptr(), str.len()}) << '"';
+ ss << '"' << printableOnly({str.ptr(), str.len()}) << '"';
break;
}
case DataType::Uint:
@@ -128,27 +147,26 @@
}
protocols::NetlinkProtocol& protocolDescr = *protocolMaybe;
- auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
- const auto msgTypeName = msgDescMaybe.has_value()
- ? msgDescMaybe->get().getMessageName(hdr->nlmsg_type)
- : std::to_string(hdr->nlmsg_type);
+ const auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
+ const auto msgDetails =
+ protocols::MessageDescriptor::getMessageDetails(msgDescMaybe, hdr->nlmsg_type);
ss << "nlmsg{" << protocolDescr.getName() << " ";
ss << "hdr={";
- ss << "type=" << msgTypeName;
+ ss << "type=" << msgDetails.name;
if (hdr->nlmsg_flags != 0) {
ss << ", flags=";
- flagsToStream(ss, hdr->nlmsg_flags);
+ flagsToStream(ss, hdr->nlmsg_flags, msgDetails.genre);
}
if (hdr->nlmsg_seq != 0) ss << ", seq=" << hdr->nlmsg_seq;
if (hdr->nlmsg_pid != 0) ss << ", pid=" << hdr->nlmsg_pid;
ss << ", len=" << hdr->nlmsg_len;
-
ss << ", crc=" << std::hex << std::setw(4) << crc16(hdr.data<uint8_t>()) << std::dec;
- ss << "} ";
+ ss << '}';
if (!printPayload) return ss.str();
+ ss << ' ';
if (!msgDescMaybe.has_value()) {
toStream(ss, hdr.data<uint8_t>());
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
index dc56643..c93d865 100644
--- a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
@@ -32,11 +32,12 @@
return find(nla_type)->second;
}
-MessageDescriptor::MessageDescriptor(const std::string& name, const MessageTypeMap&& messageTypes,
+MessageDescriptor::MessageDescriptor(const std::string& name,
+ const MessageDetailsMap&& messageDetails,
const AttributeMap&& attrTypes, size_t contentsSize)
: mName(name),
mContentsSize(contentsSize),
- mMessageTypes(messageTypes),
+ mMessageDetails(messageDetails),
mAttributeMap(attrTypes) {}
MessageDescriptor::~MessageDescriptor() {}
@@ -45,18 +46,25 @@
return mContentsSize;
}
-const MessageDescriptor::MessageTypeMap& MessageDescriptor::getMessageTypeMap() const {
- return mMessageTypes;
+const MessageDescriptor::MessageDetailsMap& MessageDescriptor::getMessageDetailsMap() const {
+ return mMessageDetails;
}
const AttributeMap& MessageDescriptor::getAttributeMap() const {
return mAttributeMap;
}
-const std::string MessageDescriptor::getMessageName(nlmsgtype_t msgtype) const {
- const auto it = mMessageTypes.find(msgtype);
- if (it == mMessageTypes.end()) return "?";
+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};
return it->second;
}
+MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(
+ const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ nlmsgtype_t msgtype) {
+ if (msgDescMaybe.has_value()) return msgDescMaybe->get().getMessageDetails(msgtype);
+ return {std::to_string(msgtype), protocols::MessageGenre::UNKNOWN};
+}
+
} // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
index ef73d09..bd0e60f 100644
--- a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
@@ -68,30 +68,53 @@
};
/**
+ * General message type's kind.
+ *
+ * For example, RTM_NEWLINK is a NEW kind. For details, please see "Flags values"
+ * section in linux/netlink.h.
+ */
+enum class MessageGenre {
+ UNKNOWN,
+ GET,
+ NEW,
+ DELETE,
+ ACK,
+};
+
+/**
* Message family descriptor.
*
* Describes the structure of all message types with the same header and attributes.
*/
class MessageDescriptor {
- protected:
- typedef std::map<nlmsgtype_t, std::string> MessageTypeMap;
-
- MessageDescriptor(const std::string& name, const MessageTypeMap&& messageTypes,
- const AttributeMap&& attrTypes, size_t contentsSize);
+ public:
+ struct MessageDetails {
+ std::string name;
+ MessageGenre genre;
+ };
+ typedef std::map<nlmsgtype_t, MessageDetails> MessageDetailsMap;
public:
virtual ~MessageDescriptor();
size_t getContentsSize() const;
- const MessageTypeMap& getMessageTypeMap() const;
+ const MessageDetailsMap& getMessageDetailsMap() const;
const AttributeMap& getAttributeMap() const;
- const std::string getMessageName(nlmsgtype_t msgtype) const;
+ MessageDetails getMessageDetails(nlmsgtype_t msgtype) const;
virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
+ static MessageDetails getMessageDetails(
+ const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+ nlmsgtype_t msgtype);
+
+ protected:
+ MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails,
+ const AttributeMap&& attrTypes, size_t contentsSize);
+
private:
const std::string mName;
const size_t mContentsSize;
- const MessageTypeMap mMessageTypes;
+ const MessageDetailsMap mMessageDetails;
const AttributeMap mAttributeMap;
};
@@ -103,11 +126,11 @@
template <typename T>
class MessageDefinition : public MessageDescriptor {
public:
- MessageDefinition(
+ MessageDefinition( //
const std::string& name,
- const std::initializer_list<MessageDescriptor::MessageTypeMap::value_type> messageTypes,
+ const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet,
const std::initializer_list<AttributeMap::value_type> attrTypes = {})
- : MessageDescriptor(name, messageTypes, attrTypes, sizeof(T)) {}
+ : MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {}
void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {
const auto& [ok, msg] = hdr.data<T>().getFirst();
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
index 4b795d9..159b6d6 100644
--- a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
@@ -42,7 +42,7 @@
const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
MessageDescriptorMap map;
for (const auto& descr : descrs) {
- for (const auto& [mtype, mname] : descr->getMessageTypeMap()) {
+ for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
map.emplace(mtype, descr);
}
}
@@ -53,7 +53,7 @@
};
for (const auto& descr : baseDescriptors) {
- for (const auto& [mtype, mname] : descr->getMessageTypeMap()) {
+ for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
map.emplace(mtype, descr);
}
}
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
index dbf10d4..8a672d3 100644
--- a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
@@ -20,9 +20,9 @@
// clang-format off
Empty::Empty() : MessageDefinition<char>("nlmsg", {
- {NLMSG_NOOP, "NOOP"},
- {NLMSG_DONE, "DONE"},
- {NLMSG_OVERRUN, "OVERRUN"},
+ {NLMSG_NOOP, {"NOOP", MessageGenre::UNKNOWN}},
+ {NLMSG_DONE, {"DONE", MessageGenre::UNKNOWN}},
+ {NLMSG_OVERRUN, {"OVERRUN", MessageGenre::UNKNOWN}},
}) {}
// clang-format on
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
index 1d6bd1c..44708a3 100644
--- a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
@@ -22,15 +22,21 @@
namespace android::nl::protocols::base {
+using DataType = AttributeDefinition::DataType;
+
// clang-format off
Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
- {NLMSG_ERROR, "ERROR"},
+ {NLMSG_ERROR, {"ERROR", MessageGenre::ACK}},
+}, {
+ {NLMSGERR_ATTR_MSG, {"MSG", DataType::String}},
+ {NLMSGERR_ATTR_OFFS, {"OFFS", DataType::Uint}},
+ {NLMSGERR_ATTR_COOKIE, {"COOKIE", DataType::Raw}},
}), mProtocol(protocol) {}
// clang-format on
void Error::toStream(std::stringstream& ss, const nlmsgerr& data) const {
ss << "nlmsgerr{error=" << data.error
- << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol) << "}";
+ << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
}
} // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
index 5203368..5b6bd97 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
@@ -22,10 +22,11 @@
nlmsgtype_t msgtype, std::string msgname,
const std::initializer_list<GenericCommandNameMap::value_type> commandNames,
const std::initializer_list<AttributeMap::value_type> attrTypes)
- : MessageDefinition<struct genlmsghdr>(msgname, {{msgtype, msgname}}, attrTypes),
+ : MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::UNKNOWN}}},
+ attrTypes),
mCommandNames(commandNames) {}
-void GenericMessageBase::toStream(std::stringstream& ss, const struct genlmsghdr& data) const {
+void GenericMessageBase::toStream(std::stringstream& ss, const genlmsghdr& data) const {
ss << "genlmsghdr{";
if (mCommandNames.count(data.cmd) == 0) {
ss << "cmd=" << unsigned(data.cmd);
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
index f3b0b31..f0ee5b0 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
@@ -22,7 +22,7 @@
namespace android::nl::protocols::generic {
-class GenericMessageBase : public MessageDefinition<struct genlmsghdr> {
+class GenericMessageBase : public MessageDefinition<genlmsghdr> {
public:
typedef std::map<uint8_t, std::string> GenericCommandNameMap;
@@ -31,7 +31,7 @@
const std::initializer_list<GenericCommandNameMap::value_type> commandNames = {},
const std::initializer_list<AttributeMap::value_type> attrTypes = {});
- void toStream(std::stringstream& ss, const struct genlmsghdr& data) const override;
+ void toStream(std::stringstream& ss, const genlmsghdr& data) const override;
private:
const GenericCommandNameMap mCommandNames;
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
index 26d3e3e..7db487a 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
@@ -25,10 +25,10 @@
using DataType = AttributeDefinition::DataType;
// clang-format off
-Link::Link() : MessageDefinition<struct ifinfomsg>("link", {
- {RTM_NEWLINK, "NEWLINK"},
- {RTM_DELLINK, "DELLINK"},
- {RTM_GETLINK, "GETLINK"},
+Link::Link() : MessageDefinition<ifinfomsg>("link", {
+ {RTM_NEWLINK, {"NEWLINK", MessageGenre::NEW}},
+ {RTM_DELLINK, {"DELLINK", MessageGenre::DELETE}},
+ {RTM_GETLINK, {"GETLINK", MessageGenre::GET}},
}, {
{IFLA_ADDRESS, {"ADDRESS"}},
{IFLA_BROADCAST, {"BROADCAST"}},
@@ -107,7 +107,7 @@
}) {}
// clang-format off
-void Link::toStream(std::stringstream& ss, const struct ifinfomsg& data) const {
+void Link::toStream(std::stringstream& ss, const ifinfomsg& data) const {
ss << "ifinfomsg{"
<< "family=" << unsigned(data.ifi_family) << ", type=" << data.ifi_type
<< ", index=" << data.ifi_index << ", flags=" << data.ifi_flags
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.h b/automotive/can/1.0/default/libnl++/protocols/route/Link.h
index 4ea3eba..ecfefc9 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/Link.h
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.h
@@ -22,10 +22,10 @@
namespace android::nl::protocols::route {
-class Link : public MessageDefinition<struct ifinfomsg> {
+class Link : public MessageDefinition<ifinfomsg> {
public:
Link();
- void toStream(std::stringstream& ss, const struct ifinfomsg& data) const override;
+ void toStream(std::stringstream& ss, const ifinfomsg& data) const override;
};
} // namespace android::nl::protocols::route