Implement nlmsg<T>
Bug: 162032964
Test: custom code to parse RTM_NEWLINK messages
Change-Id: I1ee4fb65d5b555c7665b7c42e6810efce7c726b6
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h b/automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h
new file mode 100644
index 0000000..d6a797b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h
@@ -0,0 +1,94 @@
+/*
+ * 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 <libnl++/nlbuf.h>
+
+namespace android::nl {
+
+/**
+ * In-place Netlink message parser.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message contents. The class doesn't own the underlying data, so the instance is valid as long as
+ * the source buffer is allocated and unmodified.
+ */
+template <typename T>
+class nlmsg {
+ public:
+ /**
+ * Validate buffer contents as a message carrying T data and create instance of nlmsg.
+ *
+ * \param buf Buffer containing the message.
+ * \return Parsed message or nullopt, if the buffer data is invalid.
+ */
+ static std::optional<nlmsg<T>> parse(nlbuf<nlmsghdr> buf) {
+ const auto& [nlOk, nlHeader] = buf.getFirst();
+ if (!nlOk) return std::nullopt;
+
+ const auto& [dataOk, dataHeader] = buf.data<T>().getFirst();
+ if (!dataOk) return std::nullopt;
+
+ const auto attributes = buf.data<nlattr>(sizeof(T));
+
+ return nlmsg<T>(nlHeader, dataHeader, attributes);
+ }
+
+ /**
+ * Validate buffer contents as a message of a given type and create instance of nlmsg.
+ *
+ * \param buf Buffer containing the message.
+ * \param msgtypes Acceptable message types (within a specific Netlink protocol)
+ * \return Parsed message or nullopt, if the buffer data is invalid or message type
+ * doesn't match.
+ */
+ static std::optional<nlmsg<T>> parse(nlbuf<nlmsghdr> buf, std::set<nlmsgtype_t> msgtypes) {
+ const auto& [nlOk, nlHeader] = buf.getFirst(); // we're doing it twice, but it's fine
+ if (!nlOk) return std::nullopt;
+
+ if (msgtypes.count(nlHeader.nlmsg_type) == 0) return std::nullopt;
+
+ return parse(buf);
+ }
+
+ /**
+ * Netlink message header.
+ *
+ * This is a generic Netlink header containing information such as message flags.
+ */
+ const nlmsghdr& header;
+
+ /**
+ * Netlink message data.
+ *
+ * This is a payload specific to a given message type.
+ */
+ const T& data;
+
+ /**
+ * Netlink message attributes.
+ */
+ const nlbuf<nlattr> attributes;
+
+ const T* operator->() const { return &data; }
+
+ private:
+ nlmsg(const nlmsghdr& nlHeader, const T& dataHeader, nlbuf<nlattr> attributes)
+ : header(nlHeader), data(dataHeader), attributes(attributes) {}
+};
+
+} // namespace android::nl