Move the netlink command code to a new NetlinkCommands file.
Test: bullhead builds, netd boots
Test: netd_{unit,integration}_test pass
Bug: 34873832
Change-Id: Ia6fcde63e1092a62cad1c5238bbb9a91a9f39080
diff --git a/server/NetlinkCommands.cpp b/server/NetlinkCommands.cpp
new file mode 100644
index 0000000..b580d09
--- /dev/null
+++ b/server/NetlinkCommands.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 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 <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#define LOG_TAG "Netd"
+#include <cutils/log.h>
+
+#include "NetdConstants.h"
+#include "NetlinkCommands.h"
+
+namespace android {
+namespace net {
+
+int openRtNetlinkSocket() {
+ int sock = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
+ if (sock == -1) {
+ return -errno;
+ }
+ if (connect(sock, reinterpret_cast<const sockaddr*>(&KERNEL_NLADDR),
+ sizeof(KERNEL_NLADDR)) == -1) {
+ return -errno;
+ }
+ return sock;
+}
+
+int recvNetlinkAck(int sock) {
+ struct {
+ nlmsghdr msg;
+ nlmsgerr err;
+ } response;
+
+ int ret = recv(sock, &response, sizeof(response), 0);
+
+ if (ret == -1) {
+ ret = -errno;
+ ALOGE("netlink recv failed (%s)", strerror(-ret));
+ return ret;
+ }
+
+ if (ret != sizeof(response)) {
+ ALOGE("bad netlink response message size (%d != %zu)", ret, sizeof(response));
+ return -EBADMSG;
+ }
+
+ return response.err.error; // Netlink errors are negative errno.
+}
+
+// Sends a netlink request and possibly expects an ack.
+// |iov| is an array of struct iovec that contains the netlink message payload.
+// The netlink header is generated by this function based on |action| and |flags|.
+// Returns -errno if there was an error or if the kernel reported an error.
+#ifdef __clang__
+#if __has_feature(address_sanitizer)
+__attribute__((optnone))
+#endif
+#endif
+WARN_UNUSED_RESULT int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen,
+ const NetlinkDumpCallback& callback) {
+ nlmsghdr nlmsg = {
+ .nlmsg_type = action,
+ .nlmsg_flags = flags,
+ };
+ iov[0].iov_base = &nlmsg;
+ iov[0].iov_len = sizeof(nlmsg);
+ for (int i = 0; i < iovlen; ++i) {
+ nlmsg.nlmsg_len += iov[i].iov_len;
+ }
+
+ int sock = openRtNetlinkSocket();
+ if (sock < 0) {
+ return sock;
+ }
+
+
+ int ret = 0;
+
+ if (writev(sock, iov, iovlen) == -1) {
+ ret = -errno;
+ ALOGE("netlink socket connect/writev failed (%s)", strerror(-ret));
+ close(sock);
+ return ret;
+ }
+
+ if (flags & NLM_F_ACK) {
+ ret = recvNetlinkAck(sock);
+ }
+
+ if ((flags & NLM_F_DUMP) && callback != nullptr) {
+ ret = processNetlinkDump(sock, callback);
+ }
+
+ close(sock);
+
+ return ret;
+}
+
+int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) {
+ return sendNetlinkRequest(action, flags, iov, iovlen, nullptr);
+}
+
+int processNetlinkDump(int sock, const NetlinkDumpCallback& callback) {
+ char buf[kNetlinkDumpBufferSize];
+
+ ssize_t bytesread;
+ do {
+ bytesread = read(sock, buf, sizeof(buf));
+
+ if (bytesread < 0) {
+ return -errno;
+ }
+
+ uint32_t len = bytesread;
+ for (nlmsghdr *nlh = reinterpret_cast<nlmsghdr *>(buf);
+ NLMSG_OK(nlh, len);
+ nlh = NLMSG_NEXT(nlh, len)) {
+ switch (nlh->nlmsg_type) {
+ case NLMSG_DONE:
+ callback(nullptr);
+ return 0;
+ case NLMSG_ERROR: {
+ nlmsgerr *err = reinterpret_cast<nlmsgerr *>(NLMSG_DATA(nlh));
+ return err->error;
+ }
+ default:
+ callback(nlh);
+ }
+ }
+ } while (bytesread > 0);
+
+ return 0;
+}
+
+} // namespace net
+} // namespace android