Merge changes from topics "libnl++-naming", "libnl++-socket"

* changes:
  Inclusive language for CAN bus HAL
  Netlink socket refactoring
  Update libnl++ class naming to match Android code style
  Implement attribute map.
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 8b98e5e..2efe054 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -254,7 +254,7 @@
                                satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
 
         if (rule.exclude) {
-            // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+            // Any exclude rule being satisfied invalidates the whole filter set.
             if (satisfied) return false;
         } else {
             anyNonExcludeRulePresent = true;
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index c6f1b04..ab107fd 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -20,8 +20,8 @@
 
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/NetlinkSocket.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
 
 #include <linux/can.h>
 #include <linux/can/error.h>
@@ -70,7 +70,7 @@
     struct can_bittiming bt = {};
     bt.bitrate = bitrate;
 
-    nl::NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+    nl::MessageFactory<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
 
     const auto ifidx = nametoindex(ifname);
     if (ifidx == 0) {
@@ -90,7 +90,7 @@
         }
     }
 
-    nl::NetlinkSocket sock(NETLINK_ROUTE);
+    nl::Socket sock(NETLINK_ROUTE);
     return sock.send(req) && sock.receiveAck();
 }
 
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 201909f..661e3f8 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -16,8 +16,6 @@
 
 #pragma once
 
-#include <libnl++/nlbuf.h>
-
 #include <linux/can.h>
 #include <net/if.h>
 
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index aeb5005..ed2a51e 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -20,8 +20,8 @@
 #include "ifreqs.h"
 
 #include <android-base/logging.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/NetlinkSocket.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
 
 #include <linux/can.h>
 #include <linux/rtnetlink.h>
@@ -62,8 +62,8 @@
 }
 
 bool add(std::string dev, std::string type) {
-    nl::NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK,
-                                             NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+    nl::MessageFactory<struct ifinfomsg> req(RTM_NEWLINK,
+                                             NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
     req.addattr(IFLA_IFNAME, dev);
 
     {
@@ -71,15 +71,15 @@
         req.addattr(IFLA_INFO_KIND, type);
     }
 
-    nl::NetlinkSocket sock(NETLINK_ROUTE);
+    nl::Socket sock(NETLINK_ROUTE);
     return sock.send(req) && sock.receiveAck();
 }
 
 bool del(std::string dev) {
-    nl::NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
+    nl::MessageFactory<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
     req.addattr(IFLA_IFNAME, dev);
 
-    nl::NetlinkSocket sock(NETLINK_ROUTE);
+    nl::Socket sock(NETLINK_ROUTE);
     return sock.send(req) && sock.receiveAck();
 }
 
diff --git a/automotive/can/1.0/default/libnetdevice/vlan.cpp b/automotive/can/1.0/default/libnetdevice/vlan.cpp
index e419154..3f904f0 100644
--- a/automotive/can/1.0/default/libnetdevice/vlan.cpp
+++ b/automotive/can/1.0/default/libnetdevice/vlan.cpp
@@ -19,8 +19,8 @@
 #include "common.h"
 
 #include <android-base/logging.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/NetlinkSocket.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
 
 #include <linux/rtnetlink.h>
 
@@ -33,8 +33,8 @@
         return false;
     }
 
-    nl::NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK,
-                                             NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
+    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);
 
@@ -48,7 +48,7 @@
         }
     }
 
-    nl::NetlinkSocket sock(NETLINK_ROUTE);
+    nl::Socket sock(NETLINK_ROUTE);
     return sock.send(req) && sock.receiveAck();
 }
 
diff --git a/automotive/can/1.0/default/libnl++/Android.bp b/automotive/can/1.0/default/libnl++/Android.bp
index cffefe7..4042b16 100644
--- a/automotive/can/1.0/default/libnl++/Android.bp
+++ b/automotive/can/1.0/default/libnl++/Android.bp
@@ -31,8 +31,9 @@
         "protocols/MessageDefinition.cpp",
         "protocols/NetlinkProtocol.cpp",
         "protocols/all.cpp",
-        "NetlinkRequest.cpp",
-        "NetlinkSocket.cpp",
+        "Attributes.cpp",
+        "MessageFactory.cpp",
+        "Socket.cpp",
         "common.cpp",
         "printer.cpp",
     ],
diff --git a/automotive/can/1.0/default/libnl++/Attributes.cpp b/automotive/can/1.0/default/libnl++/Attributes.cpp
new file mode 100644
index 0000000..c101647
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Attributes.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include <libnl++/Attributes.h>
+
+namespace android::nl {
+
+Attributes::Attributes() {}
+
+Attributes::Attributes(Buffer<nlattr> buffer) : Buffer<nlattr>(buffer) {}
+
+const Attributes::Index& Attributes::index() const {
+    if (mIndex.has_value()) return *mIndex;
+
+    mIndex = Index();
+    auto& index = *mIndex;
+
+    for (auto attr : static_cast<Buffer<nlattr>>(*this)) {
+        index.emplace(attr->nla_type, attr);
+    }
+
+    return index;
+}
+
+bool Attributes::contains(nlattrtype_t attrtype) const {
+    return index().count(attrtype) > 0;
+}
+
+/* Parser specializations for selected types (more to come if necessary). */
+
+template <>
+Attributes Attributes::parse(Buffer<nlattr> buf) {
+    return buf.data<nlattr>();
+}
+
+template <>
+std::string Attributes::parse(Buffer<nlattr> buf) {
+    const auto rawString = buf.data<char>().getRaw();
+    return std::string(rawString.ptr(), rawString.len());
+}
+
+template <typename T>
+static T parseUnsigned(Buffer<nlattr> buf) {
+    return buf.data<T>().copyFirst();
+}
+
+template <>
+uint8_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint8_t>(buf);
+}
+
+template <>
+uint16_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint16_t>(buf);
+}
+
+template <>
+uint32_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint32_t>(buf);
+}
+
+template <>
+uint64_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint64_t>(buf);
+}
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/NetlinkRequest.cpp b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
similarity index 97%
rename from automotive/can/1.0/default/libnl++/NetlinkRequest.cpp
rename to automotive/can/1.0/default/libnl++/MessageFactory.cpp
index b12489c..0c6a331 100644
--- a/automotive/can/1.0/default/libnl++/NetlinkRequest.cpp
+++ b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <libnl++/NetlinkRequest.h>
+#include <libnl++/MessageFactory.h>
 
 #include <android-base/logging.h>
 
diff --git a/automotive/can/1.0/default/libnl++/NetlinkSocket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
similarity index 63%
rename from automotive/can/1.0/default/libnl++/NetlinkSocket.cpp
rename to automotive/can/1.0/default/libnl++/Socket.cpp
index 6f0f0c2..56e990c 100644
--- a/automotive/can/1.0/default/libnl++/NetlinkSocket.cpp
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <libnl++/NetlinkSocket.h>
+#include <libnl++/Socket.h>
 
 #include <libnl++/printer.h>
 
@@ -27,8 +27,7 @@
  */
 static constexpr bool kSuperVerbose = false;
 
-NetlinkSocket::NetlinkSocket(int protocol, unsigned int pid, uint32_t groups)
-    : mProtocol(protocol) {
+Socket::Socket(int protocol, unsigned pid, uint32_t groups) : mProtocol(protocol) {
     mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
     if (!mFd.ok()) {
         PLOG(ERROR) << "Can't open Netlink socket";
@@ -48,88 +47,65 @@
     }
 }
 
-bool NetlinkSocket::send(nlmsghdr* nlmsg, size_t totalLen) {
+bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
     if constexpr (kSuperVerbose) {
-        nlmsg->nlmsg_seq = mSeq;
-        LOG(VERBOSE) << (mFailed ? "(not) " : "")
-                     << "sending Netlink message: " << toString({nlmsg, totalLen}, mProtocol);
+        LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending Netlink message ("  //
+                     << msg->nlmsg_pid << " -> " << sa.nl_pid << "): " << toString(msg, mProtocol);
     }
-
     if (mFailed) return false;
 
-    nlmsg->nlmsg_pid = 0;  // kernel
-    nlmsg->nlmsg_seq = mSeq++;
-    nlmsg->nlmsg_flags |= NLM_F_ACK;
-
-    iovec iov = {nlmsg, nlmsg->nlmsg_len};
-
-    sockaddr_nl sa = {};
-    sa.nl_family = AF_NETLINK;
-
-    msghdr msg = {};
-    msg.msg_name = &sa;
-    msg.msg_namelen = sizeof(sa);
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-
-    if (sendmsg(mFd.get(), &msg, 0) < 0) {
-        PLOG(ERROR) << "Can't send Netlink message";
-        return false;
-    }
-    return true;
-}
-
-bool NetlinkSocket::send(const nlbuf<nlmsghdr>& msg, const sockaddr_nl& sa) {
-    if constexpr (kSuperVerbose) {
-        LOG(VERBOSE) << (mFailed ? "(not) " : "")
-                     << "sending Netlink message: " << toString(msg, mProtocol);
-    }
-
-    if (mFailed) return false;
+    mSeq = msg->nlmsg_seq;
     const auto rawMsg = msg.getRaw();
     const auto bytesSent = sendto(mFd.get(), rawMsg.ptr(), rawMsg.len(), 0,
                                   reinterpret_cast<const sockaddr*>(&sa), sizeof(sa));
     if (bytesSent < 0) {
         PLOG(ERROR) << "Can't send Netlink message";
         return false;
+    } else if (size_t(bytesSent) != rawMsg.len()) {
+        LOG(ERROR) << "Can't send Netlink message: truncated message";
+        return false;
     }
     return true;
 }
 
-std::optional<nlbuf<nlmsghdr>> NetlinkSocket::receive(void* buf, size_t bufLen) {
-    sockaddr_nl sa = {};
-    return receive(buf, bufLen, sa);
+std::optional<Buffer<nlmsghdr>> Socket::receive(size_t maxSize) {
+    return receiveFrom(maxSize).first;
 }
 
-std::optional<nlbuf<nlmsghdr>> NetlinkSocket::receive(void* buf, size_t bufLen, sockaddr_nl& sa) {
-    if (mFailed) return std::nullopt;
+std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> Socket::receiveFrom(size_t maxSize) {
+    if (mFailed) return {std::nullopt, {}};
 
-    socklen_t saLen = sizeof(sa);
-    if (bufLen == 0) {
-        LOG(ERROR) << "Receive buffer has zero size!";
-        return std::nullopt;
+    if (maxSize == 0) {
+        LOG(ERROR) << "Maximum receive size should not be zero";
+        return {std::nullopt, {}};
     }
-    const auto bytesReceived =
-            recvfrom(mFd.get(), buf, bufLen, MSG_TRUNC, reinterpret_cast<sockaddr*>(&sa), &saLen);
+    if (mReceiveBuffer.size() < maxSize) mReceiveBuffer.resize(maxSize);
+
+    sockaddr_nl sa = {};
+    socklen_t saLen = sizeof(sa);
+    const auto bytesReceived = recvfrom(mFd.get(), mReceiveBuffer.data(), maxSize, MSG_TRUNC,
+                                        reinterpret_cast<sockaddr*>(&sa), &saLen);
+
     if (bytesReceived <= 0) {
         PLOG(ERROR) << "Failed to receive Netlink message";
-        return std::nullopt;
-    } else if (unsigned(bytesReceived) > bufLen) {
-        PLOG(ERROR) << "Received data larger than the receive buffer! " << bytesReceived << " > "
-                    << bufLen;
-        return std::nullopt;
+        return {std::nullopt, {}};
+    } else if (size_t(bytesReceived) > maxSize) {
+        PLOG(ERROR) << "Received data larger than maximum receive size: "  //
+                    << bytesReceived << " > " << maxSize;
+        return {std::nullopt, {}};
     }
 
-    nlbuf<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(buf), bytesReceived);
+    Buffer<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(mReceiveBuffer.data()), bytesReceived);
     if constexpr (kSuperVerbose) {
-        LOG(VERBOSE) << "received " << toString(msg, mProtocol);
+        LOG(VERBOSE) << "received (" << sa.nl_pid << " -> " << msg->nlmsg_pid << "):"  //
+                     << toString(msg, mProtocol);
     }
-    return msg;
+    return {msg, sa};
 }
 
 /* TODO(161389935): Migrate receiveAck to use nlmsg<> internally. Possibly reuse
- * NetlinkSocket::receive(). */
-bool NetlinkSocket::receiveAck() {
+ * Socket::receive(). */
+bool Socket::receiveAck() {
     if (mFailed) return false;
 
     char buf[8192];
@@ -180,11 +156,11 @@
     return false;
 }
 
-std::optional<unsigned int> NetlinkSocket::getSocketPid() {
+std::optional<unsigned> Socket::getPid() {
     sockaddr_nl sa = {};
     socklen_t sasize = sizeof(sa);
     if (getsockname(mFd.get(), reinterpret_cast<sockaddr*>(&sa), &sasize) < 0) {
-        PLOG(ERROR) << "Failed to getsockname() for netlink_fd!";
+        PLOG(ERROR) << "Failed to get PID of Netlink socket";
         return std::nullopt;
     }
     return sa.nl_pid;
diff --git a/automotive/can/1.0/default/libnl++/common.cpp b/automotive/can/1.0/default/libnl++/common.cpp
index 7848646..74eee24 100644
--- a/automotive/can/1.0/default/libnl++/common.cpp
+++ b/automotive/can/1.0/default/libnl++/common.cpp
@@ -41,7 +41,7 @@
     return str;
 }
 
-uint16_t crc16(const nlbuf<uint8_t> data, uint16_t crc) {
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc) {
     for (const auto byte : data.getRaw()) {
         crc ^= byte;
         for (unsigned i = 0; i < 8; i++) {
diff --git a/automotive/can/1.0/default/libnl++/common.h b/automotive/can/1.0/default/libnl++/common.h
index dc5777c..1d9dbab 100644
--- a/automotive/can/1.0/default/libnl++/common.h
+++ b/automotive/can/1.0/default/libnl++/common.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
 
 #include <linux/can.h>
 #include <net/if.h>
@@ -54,6 +54,6 @@
  * \param crc Previous CRC16 value to continue calculating running checksum
  * \return CRC16 checksum
  */
-uint16_t crc16(const nlbuf<uint8_t> data, uint16_t crc = 0);
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc = 0);
 
 }  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
new file mode 100644
index 0000000..f16d997
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
@@ -0,0 +1,170 @@
+/*
+ * 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 <android-base/logging.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+#include <utils/Mutex.h>
+
+#include <map>
+
+namespace android::nl {
+
+/**
+ * Netlink attribute map.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message attributes. The class doesn't own the underlying data, so the instance is valid as long
+ * as the source buffer is allocated and unmodified.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
+ */
+class Attributes : private Buffer<nlattr> {
+  public:
+    /**
+     * Constructs empty attribute map.
+     */
+    Attributes();
+
+    /**
+     * Construct attribute map from underlying buffer.
+     *
+     * \param buffer Source buffer pointing at the first attribute.
+     */
+    Attributes(Buffer<nlattr> buffer);
+
+    /**
+     * Checks, if the map contains given attribute type (key).
+     *
+     * \param attrtype Attribute type (such as IFLA_IFNAME).
+     * \return true if attribute is in the map, false otherwise.
+     */
+    bool contains(nlattrtype_t attrtype) const;
+
+    /**
+     * Fetches attribute of a given type by copying it.
+     *
+     * While this is quite efficient for simple types, fetching nested attribute creates a new copy
+     * of child attribute map. This may be costly if you calculate the index for child maps multiple
+     * times. Examples below.
+     *
+     * BAD:
+     * ```
+     * const auto flags = msg->attributes.
+     *     get<nl::Attributes>(IFLA_AF_SPEC).
+     *     get<nl::Attributes>(AF_INET6).  // IFLA_AF_SPEC index lazy-calculated
+     *     get<uint32_t>(IFLA_INET6_FLAGS);  // AF_INET6 index lazy-calculated
+     * const auto& cacheinfo = msg->attributes.
+     *     get<nl::Attributes>(IFLA_AF_SPEC).  // new instance of IFLA_AF_SPEC index
+     *     get<nl::Attributes>(AF_INET6).  // IFLA_AF_SPEC index calculated again
+     *     getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO);  // AF_INET6 calculated again
+     * ```
+     *
+     * GOOD:
+     * ```
+     * const auto inet6 = msg->attributes.
+     *     get<nl::Attributes>(IFLA_AF_SPEC).
+     *     get<nl::Attributes>(AF_INET6);
+     * const auto flags = inet6.get<uint32_t>(IFLA_INET6_FLAGS);  // AF_INET6 index lazy-calculated
+     * const auto& cache = inet6.getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO);  // index reused
+     * ```
+     *
+     * If the attribute doesn't exists, default value of a given type is returned and warning
+     * spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+     *
+     * \param attrtype Attribute to fetch.
+     * \return Attribute value.
+     */
+    template <typename T>
+    T get(nlattrtype_t attrtype) const {
+        const auto& ind = index();
+        const auto it = ind.find(attrtype);
+        if (it == ind.end()) {
+            LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+            return T{};
+        }
+
+        return parse<T>(it->second);
+    }
+
+    /**
+     * Fetches a reference to a given attribute's data.
+     *
+     * This method is intended for arbitrary structures not specialized with get(nlattrtype_t)
+     * template and slightly more efficient for larger payloads due to not copying its data.
+     *
+     * If the attribute doesn't exists, a reference to empty value of a given type is returned and
+     * warning spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+     *
+     * \param attrtype Attribute to fetch.
+     * \return Reference to the attribute's data.
+     */
+    template <typename T>
+    const T& getStruct(nlattrtype_t attrtype) const {
+        const auto& ind = index();
+        const auto it = ind.find(attrtype);
+        if (it == ind.end()) {
+            LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+            static const T empty = {};
+            return empty;
+        }
+
+        const auto& [ok, val] = it->second.data<T>().getFirst();
+        if (!ok) LOG(WARNING) << "Can't fetch structure of size " << sizeof(T);
+        return val;
+    }
+
+  private:
+    using Index = std::map<nlattrtype_t, Buffer<nlattr>>;
+
+    /**
+     * Attribute index.
+     *
+     * Since this field is not protected by mutex, the use of \see index() dependent methods
+     * (such as \see get(nlattrtype_t)) is not thread-safe. This is a compromise made based on the
+     * following assumptions:
+     *
+     * 1. Most (or even all) use-cases involve attribute parsing in the same thread as where the
+     *    buffer was allocated. This is partly forced by a dependence of nlmsg lifecycle on the
+     *    underlying data buffer.
+     *
+     * 2. Index calculation and access would come with performance penalty never justified in most
+     *    or all use cases (see the previous point). Since Index is not a trivially assignable data
+     *    structure, it's not possible to use it with atomic types only and avoid mutexes.
+     */
+    mutable std::optional<Index> mIndex;
+
+    /**
+     * Lazy-calculate and cache index.
+     *
+     * \return Attribute index.
+     */
+    const Index& index() const;
+
+    /**
+     * Parse attribute data into a specific type.
+     *
+     * \param buf Raw attribute data.
+     * \return Parsed data.
+     */
+    template <typename T>
+    static T parse(Buffer<nlattr> buf);
+};
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
similarity index 80%
rename from automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h
rename to automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
index 4c0e581..a6f8f7a 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/nlbuf.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
@@ -25,7 +25,7 @@
 namespace android::nl {
 
 /**
- * Buffer containing netlink structure (e.g. struct nlmsghdr, struct nlattr).
+ * Buffer wrapper containing netlink structure (e.g. struct nlmsghdr, struct nlattr).
  *
  * This is a C++-style, memory safe(r) and generic implementation of linux/netlink.h macros.
  *
@@ -33,7 +33,7 @@
  * not be trusted - the value may either be larger than the buffer message is allocated in or
  * smaller than the header itself (so it couldn't even fit itself).
  *
- * As a solution, nlbuf<> keeps track of two lengths (both attribute for header with payload):
+ * As a solution, Buffer<> keeps track of two lengths (both attribute for header with payload):
  * - buffer length - how much memory was allocated to a given structure
  * - declared length - what nlmsg_len or nla_len says how long the structure is
  *
@@ -42,7 +42,7 @@
  * this template attempts to protect against.
  */
 template <typename T>
-class nlbuf {
+class Buffer {
     // The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h
 
     static constexpr size_t alignto = NLMSG_ALIGNTO;
@@ -54,12 +54,17 @@
 
   public:
     /**
-     * Constructor for nlbuf.
-     *
-     * \param data A pointer to the data the nlbuf wraps.
-     * \param bufferLen Length of buffer.
+     * Constructs empty buffer of size 0.
      */
-    nlbuf(const T* data, size_t bufferLen) : mData(data), mBufferEnd(pointerAdd(data, bufferLen)) {}
+    Buffer() : mData(nullptr), mBufferEnd(nullptr) {}
+
+    /**
+     * Buffer constructor.
+     *
+     * \param data A pointer to the data the Buffer wraps.
+     * \param bufLen Length of the buffer.
+     */
+    Buffer(const T* data, size_t bufLen) : mData(data), mBufferEnd(pointerAdd(data, bufLen)) {}
 
     const T* operator->() const {
         CHECK(firstOk()) << "buffer can't fit the first element's header";
@@ -68,8 +73,8 @@
 
     std::pair<bool, const T&> getFirst() const {
         if (!ok()) {
-            static const T dummy = {};
-            return {false, dummy};
+            static const T empty = {};
+            return {false, empty};
         }
         return {true, *mData};
     }
@@ -78,7 +83,8 @@
      * Copy the first element of the buffer.
      *
      * This is a memory-safe cast operation, useful for reading e.g. uint32_t values
-     * from 1-byte buffer.
+     * from 1-byte buffer. If the buffer is smaller than the copied type, the rest is
+     * padded with default constructor output (usually zeros).
      */
     T copyFirst() const {
         T val = {};
@@ -89,7 +95,7 @@
     bool firstOk() const { return sizeof(T) <= remainingLength(); }
 
     template <typename D>
-    const nlbuf<D> data(size_t offset = 0) const {
+    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()};
@@ -100,7 +106,7 @@
         iterator() : mCurrent(nullptr, size_t(0)) {
             CHECK(!mCurrent.ok()) << "end() iterator should indicate it's beyond end";
         }
-        iterator(const nlbuf<T>& buf) : mCurrent(buf) {}
+        iterator(const Buffer<T>& buf) : mCurrent(buf) {}
 
         iterator operator++() {
             // mBufferEnd stays the same
@@ -117,10 +123,10 @@
             return uintptr_t(other.mCurrent.mData) == uintptr_t(mCurrent.mData);
         }
 
-        const nlbuf<T>& operator*() const { return mCurrent; }
+        const Buffer<T>& operator*() const { return mCurrent; }
 
       protected:
-        nlbuf<T> mCurrent;
+        Buffer<T> mCurrent;
     };
     iterator begin() const { return {*this}; }
     iterator end() const { return {}; }
@@ -136,7 +142,7 @@
 
     class raw_view {
       public:
-        raw_view(const nlbuf<T>& buffer) : mBuffer(buffer) {}
+        raw_view(const Buffer<T>& buffer) : mBuffer(buffer) {}
         raw_iterator begin() const { return {mBuffer}; }
         raw_iterator end() const { return {}; }
 
@@ -144,7 +150,7 @@
         size_t len() const { return mBuffer.remainingLength(); }
 
       private:
-        const nlbuf<T> mBuffer;
+        const Buffer<T> mBuffer;
     };
 
     raw_view getRaw() const { return {*this}; }
@@ -153,7 +159,7 @@
     const T* mData;
     const void* mBufferEnd;
 
-    nlbuf(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
+    Buffer(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
 
     bool ok() const { return declaredLength() <= remainingLength(); }
 
@@ -186,16 +192,16 @@
     }
 
     template <typename D>
-    friend class nlbuf;  // calling private constructor of data buffers
+    friend class Buffer;  // calling private constructor of data buffers
 };
 
 template <>
-inline size_t nlbuf<nlmsghdr>::declaredLengthImpl() const {
+inline size_t Buffer<nlmsghdr>::declaredLengthImpl() const {
     return mData->nlmsg_len;
 }
 
 template <>
-inline size_t nlbuf<nlattr>::declaredLengthImpl() const {
+inline size_t Buffer<nlattr>::declaredLengthImpl() const {
     return mData->nla_len;
 }
 
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
similarity index 78%
rename from automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h
rename to automotive/can/1.0/default/libnl++/include/libnl++/Message.h
index d6a797b..2b84a86 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/nlmsg.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
@@ -16,7 +16,8 @@
 
 #pragma once
 
-#include <libnl++/nlbuf.h>
+#include <libnl++/Attributes.h>
+#include <libnl++/Buffer.h>
 
 namespace android::nl {
 
@@ -26,17 +27,20 @@
  * 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.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
  */
 template <typename T>
-class nlmsg {
+class Message {
   public:
     /**
-     * Validate buffer contents as a message carrying T data and create instance of nlmsg.
+     * Validate buffer contents as a message carrying T data and create instance of parsed message.
      *
      * \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) {
+    static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf) {
         const auto& [nlOk, nlHeader] = buf.getFirst();
         if (!nlOk) return std::nullopt;
 
@@ -45,18 +49,18 @@
 
         const auto attributes = buf.data<nlattr>(sizeof(T));
 
-        return nlmsg<T>(nlHeader, dataHeader, attributes);
+        return Message<T>(nlHeader, dataHeader, attributes);
     }
 
     /**
-     * Validate buffer contents as a message of a given type and create instance of nlmsg.
+     * Validate buffer contents as a message of a given type and create instance of parsed message.
      *
      * \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) {
+    static std::optional<Message<T>> parse(Buffer<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;
 
@@ -82,12 +86,12 @@
     /**
      * Netlink message attributes.
      */
-    const nlbuf<nlattr> attributes;
+    const Attributes attributes;
 
     const T* operator->() const { return &data; }
 
   private:
-    nlmsg(const nlmsghdr& nlHeader, const T& dataHeader, nlbuf<nlattr> attributes)
+    Message(const nlmsghdr& nlHeader, const T& dataHeader, Attributes attributes)
         : header(nlHeader), data(dataHeader), attributes(attributes) {}
 };
 
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkRequest.h b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
similarity index 92%
rename from automotive/can/1.0/default/libnl++/include/libnl++/NetlinkRequest.h
rename to automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
index 29c3601..5272577 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkRequest.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
@@ -25,7 +25,7 @@
 
 namespace android::nl {
 
-/** Implementation details, do not use outside NetlinkRequest template. */
+/** 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,
@@ -35,7 +35,6 @@
 
 }  // namespace impl
 
-// TODO(twasilczyk): rename to NetlinkMessage
 /**
  * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
  *
@@ -43,7 +42,7 @@
  * \param BUFSIZE how much space to reserve for payload (not counting the header size)
  */
 template <class T, unsigned int BUFSIZE = 128>
-struct NetlinkRequest {
+struct MessageFactory {
     struct RequestData {
         struct nlmsghdr nlmsg;
         T data;
@@ -58,7 +57,7 @@
      * \param type Message type (such as RTM_NEWLINK)
      * \param flags Message flags (such as NLM_F_REQUEST)
      */
-    NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
+    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;
@@ -96,11 +95,11 @@
 
     /** Guard class to frame nested attributes. See nest(int). */
     struct Nest {
-        Nest(NetlinkRequest& req, nlattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
+        Nest(MessageFactory& req, nlattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
         ~Nest() { mReq.nestEnd(mAttr); }
 
       private:
-        NetlinkRequest& mReq;
+        MessageFactory& mReq;
         struct nlattr* mAttr;
 
         DISALLOW_COPY_AND_ASSIGN(Nest);
@@ -114,7 +113,7 @@
      *
      * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
      * inside IFLA_LINKINFO:
-     *    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+     *    MessageFactory<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
      *    {
      *        auto linkinfo = req.nest(IFLA_LINKINFO);
      *        req.addattr(IFLA_INFO_KIND, "can");
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkSocket.h b/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkSocket.h
deleted file mode 100644
index f2a38fb..0000000
--- a/automotive/can/1.0/default/libnl++/include/libnl++/NetlinkSocket.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2019 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 <android-base/macros.h>
-#include <android-base/unique_fd.h>
-#include <libnl++/NetlinkRequest.h>
-#include <libnl++/nlbuf.h>
-
-#include <linux/netlink.h>
-
-#include <optional>
-
-namespace android::nl {
-
-/**
- * A wrapper around AF_NETLINK sockets.
- *
- * This class is not thread safe to use a single instance between multiple threads, but it's fine to
- * use multiple instances over multiple threads.
- */
-struct NetlinkSocket {
-    /**
-     * NetlinkSocket constructor.
-     *
-     * \param protocol the Netlink protocol to use.
-     * \param pid port id. Default value of 0 allows the kernel to assign us a unique pid. (NOTE:
-     * this is NOT the same as process id!)
-     * \param groups Netlink multicast groups to listen to. This is a 32-bit bitfield, where each
-     * bit is a different group. Default value of 0 means no groups are selected. See man netlink.7
-     * for more details.
-     */
-    NetlinkSocket(int protocol, unsigned int pid = 0, uint32_t groups = 0);
-
-    /**
-     * Send Netlink message to Kernel. The sequence number will be automatically incremented, and
-     * the NLM_F_ACK (request ACK) flag will be set.
-     *
-     * \param msg Message to send.
-     * \return true, if succeeded
-     */
-    template <class T, unsigned int BUFSIZE>
-    bool send(NetlinkRequest<T, BUFSIZE>& req) {
-        if (!req.isGood()) return false;
-        return send(req.header(), req.totalLength);
-    }
-
-    /**
-     * Send Netlink message. The message will be sent as is, without any modification.
-     *
-     * \param msg Message to send.
-     * \param sa Destination address.
-     * \return true, if succeeded
-     */
-    bool send(const nlbuf<nlmsghdr>& msg, const sockaddr_nl& sa);
-
-    /**
-     * Receive Netlink data.
-     *
-     * \param buf buffer to hold message data.
-     * \param bufLen length of buf.
-     * \return nlbuf with message data, std::nullopt on error.
-     */
-    std::optional<nlbuf<nlmsghdr>> receive(void* buf, size_t bufLen);
-
-    /**
-     * Receive Netlink data with address info.
-     *
-     * \param buf buffer to hold message data.
-     * \param bufLen length of buf.
-     * \param sa Blank struct that recvfrom will populate with address info.
-     * \return nlbuf with message data, std::nullopt on error.
-     */
-    std::optional<nlbuf<nlmsghdr>> receive(void* buf, size_t bufLen, sockaddr_nl& sa);
-
-    /**
-     * Receive Netlink ACK message from Kernel.
-     *
-     * \return true if received ACK message, false in case of error
-     */
-    bool receiveAck();
-
-    /**
-     * Gets the PID assigned to mFd.
-     *
-     * \return pid that mSocket is bound to.
-     */
-    std::optional<unsigned int> getSocketPid();
-
-  private:
-    const int mProtocol;
-
-    uint32_t mSeq = 0;
-    base::unique_fd mFd;
-    bool mFailed = false;
-
-    bool send(nlmsghdr* msg, size_t totalLen);
-
-    DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
-};
-
-}  // 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
new file mode 100644
index 0000000..bc6ad9d
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2019 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 <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/MessageFactory.h>
+
+#include <linux/netlink.h>
+
+#include <optional>
+#include <vector>
+
+namespace android::nl {
+
+/**
+ * A wrapper around AF_NETLINK sockets.
+ *
+ * This class is not thread safe to use a single instance between multiple threads, but it's fine to
+ * use multiple instances over multiple threads.
+ */
+class Socket {
+  public:
+    static constexpr size_t defaultReceiveSize = 8192;
+
+    /**
+     * Socket constructor.
+     *
+     * \param protocol the Netlink protocol to use.
+     * \param pid port id. Default value of 0 allows the kernel to assign us a unique pid.
+     *        (NOTE: this is NOT the same as process id).
+     * \param groups Netlink multicast groups to listen to. This is a 32-bit bitfield, where each
+     *        bit is a different group. Default value of 0 means no groups are selected.
+     *        See man netlink.7.
+     * for more details.
+     */
+    Socket(int protocol, unsigned pid = 0, uint32_t groups = 0);
+
+    /**
+     * Send Netlink message with incremented sequence number to the Kernel.
+     *
+     * \param msg Message to send. Its sequence number will be updated.
+     * \return true, if succeeded.
+     */
+    template <class T, unsigned BUFSIZE>
+    bool send(MessageFactory<T, BUFSIZE>& req) {
+        sockaddr_nl sa = {};
+        sa.nl_family = AF_NETLINK;
+        sa.nl_pid = 0;  // Kernel
+        return send(req, sa);
+    }
+
+    /**
+     * Send Netlink message with incremented sequence number.
+     *
+     * \param msg Message to send. Its sequence number will be updated.
+     * \param sa Destination address.
+     * \return true, if succeeded.
+     */
+    template <class T, unsigned BUFSIZE>
+    bool send(MessageFactory<T, BUFSIZE>& req, const sockaddr_nl& sa) {
+        if (!req.isGood()) return false;
+
+        const auto nlmsg = req.header();
+        nlmsg->nlmsg_seq = mSeq + 1;
+
+        // With MessageFactory<>, we trust nlmsg_len to be correct.
+        return send({nlmsg, nlmsg->nlmsg_len}, sa);
+    }
+
+    /**
+     * Send Netlink message.
+     *
+     * \param msg Message to send.
+     * \param sa Destination address.
+     * \return true, if succeeded.
+     */
+    bool send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa);
+
+    /**
+     * Receive one or multiple Netlink messages.
+     *
+     * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+     * call to the read function or until deallocation of Socket instance.
+     *
+     * \param maxSize Maximum total size of received messages
+     * \return Buffer view with message data, std::nullopt on error.
+     */
+    std::optional<Buffer<nlmsghdr>> receive(size_t maxSize = defaultReceiveSize);
+
+    /**
+     * Receive one or multiple Netlink messages and the sender process address.
+     *
+     * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+     * call to the read function or until deallocation of Socket instance.
+     *
+     * \param maxSize Maximum total size of received messages
+     * \return A pair (for use with structured binding) containing:
+     *         - buffer view with message data, std::nullopt on error;
+     *         - sender process address.
+     */
+    std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> receiveFrom(
+            size_t maxSize = defaultReceiveSize);
+
+    /**
+     * Receive Netlink ACK message from Kernel.
+     *
+     * \return true if received ACK message, false in case of error
+     */
+    bool receiveAck();
+
+    /**
+     * Fetches the socket PID.
+     *
+     * \return PID that socket is bound to.
+     */
+    std::optional<unsigned> getPid();
+
+  private:
+    const int mProtocol;
+
+    uint32_t mSeq = 0;
+    base::unique_fd mFd;
+    bool mFailed = false;
+    std::vector<uint8_t> mReceiveBuffer;
+
+    DISALLOW_COPY_AND_ASSIGN(Socket);
+};
+
+}  // namespace android::nl
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 7167965..53a06d8 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
 
 #include <linux/netlink.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 nlbuf<nlmsghdr> hdr, int protocol, bool printPayload = false);
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload = false);
 
 }  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/printer.cpp b/automotive/can/1.0/default/libnl++/printer.cpp
index c32afb3..9735db1 100644
--- a/automotive/can/1.0/default/libnl++/printer.cpp
+++ b/automotive/can/1.0/default/libnl++/printer.cpp
@@ -20,7 +20,7 @@
 #include "protocols/all.h"
 
 #include <android-base/logging.h>
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
 
 #include <algorithm>
 #include <iomanip>
@@ -61,7 +61,7 @@
     }
 }
 
-static void toStream(std::stringstream& ss, const nlbuf<uint8_t> data) {
+static void toStream(std::stringstream& ss, const Buffer<uint8_t> data) {
     const auto rawData = data.getRaw();
     const auto dataLen = rawData.len();
     ss << std::hex;
@@ -77,7 +77,7 @@
     if (dataLen > 16) ss << std::endl;
 }
 
-static void toStream(std::stringstream& ss, const nlbuf<nlattr> attr,
+static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
                      const protocols::AttributeMap& attrMap) {
     using DataType = protocols::AttributeDefinition::DataType;
     const auto attrtype = attrMap[attr->nla_type];
@@ -115,7 +115,7 @@
     }
 }
 
-std::string toString(const nlbuf<nlmsghdr> hdr, int protocol, bool printPayload) {
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload) {
     if (!hdr.firstOk()) return "nlmsg{buffer overflow}";
 
     std::stringstream ss;
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
index 046ef47..ef73d09 100644
--- a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
 #include <libnl++/types.h>
 
 #include <map>
@@ -60,7 +60,7 @@
         Uint,
         Struct,
     };
-    using ToStream = std::function<void(std::stringstream& ss, const nlbuf<nlattr> attr)>;
+    using ToStream = std::function<void(std::stringstream& ss, const Buffer<nlattr> attr)>;
 
     std::string name;
     DataType dataType = DataType::Raw;
@@ -86,7 +86,7 @@
     const MessageTypeMap& getMessageTypeMap() const;
     const AttributeMap& getAttributeMap() const;
     const std::string getMessageName(nlmsgtype_t msgtype) const;
-    virtual void dataToStream(std::stringstream& ss, const nlbuf<nlmsghdr> hdr) const = 0;
+    virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
 
   private:
     const std::string mName;
@@ -109,7 +109,7 @@
             const std::initializer_list<AttributeMap::value_type> attrTypes = {})
         : MessageDescriptor(name, messageTypes, attrTypes, sizeof(T)) {}
 
-    void dataToStream(std::stringstream& ss, const nlbuf<nlmsghdr> hdr) const override {
+    void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {
         const auto& [ok, msg] = hdr.data<T>().getFirst();
         if (!ok) {
             ss << "{incomplete payload}";
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp b/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
index ea923bb..b62cec3 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
@@ -18,7 +18,7 @@
 
 namespace android::nl::protocols::route {
 
-void mapToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
     const auto& [ok, data] = attr.data<rtnl_link_ifmap>().getFirst();
     if (!ok) {
         ss << "invalid structure";
@@ -33,7 +33,7 @@
        << unsigned(data.port) << '}';
 }
 
-void ifla_cacheinfoToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
     const auto& [ok, data] = attr.data<ifla_cacheinfo>().getFirst();
     if (!ok) {
         ss << "invalid structure";
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.h b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
index 38776fa..b9d622a 100644
--- a/automotive/can/1.0/default/libnl++/protocols/route/structs.h
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <libnl++/nlbuf.h>
+#include <libnl++/Buffer.h>
 
 #include <linux/rtnetlink.h>
 
@@ -25,13 +25,13 @@
 namespace android::nl::protocols::route {
 
 // rtnl_link_ifmap
-void mapToStream(std::stringstream& ss, const nlbuf<nlattr> attr);
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr);
 
 // ifla_cacheinfo
-void ifla_cacheinfoToStream(std::stringstream& ss, const nlbuf<nlattr> attr);
+void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr);
 
 template <typename T>
-void arrayToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
     ss << '{';
     for (const auto it : attr.data<T>().getRaw()) {
         ss << it << ',';
@@ -42,7 +42,7 @@
 
 // rtnl_link_stats or rtnl_link_stats64
 template <typename T>
-void statsToStream(std::stringstream& ss, const nlbuf<nlattr> attr) {
+void statsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
     const auto& [ok, data] = attr.data<T>().getFirst();
     if (!ok) {
         ss << "invalid structure";
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index 8dfd7d6..fc77579 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -86,7 +86,7 @@
         EXPECT_EQ(ICanController::Result::OK, result);
 
         /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
-         * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+         * file -- this is a test, so we don't want to add fake services to a device manifest. */
         auto manager = hidl::manager::V1_2::IServiceManager::getService();
         auto service = manager->get(ICanBus::descriptor, config.name);
         mBus = ICanBus::castFrom(service);
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index b945978..294cd17 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -119,7 +119,7 @@
 
 void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
     /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
-     * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+     * file -- this is a test, so we don't want to add fake services to a device manifest. */
     auto manager = hidl::manager::V1_2::IServiceManager::getService();
     auto busService = manager->get(ICanBus::descriptor, srvname);
     ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
@@ -145,7 +145,7 @@
     assertRegistered(name, false);
 }
 
-TEST_P(CanControllerHalTest, DownDummy) {
+TEST_P(CanControllerHalTest, DownFake) {
     const auto result = mCanController->downInterface("imnotup");
     ASSERT_FALSE(result);
 }