blob: b580d09d101089a4c0ffe1bde654205297e1f028 [file] [log] [blame]
Lorenzo Colitti1ef549d2017-02-13 18:32:09 +09001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <unistd.h>
19#include <sys/socket.h>
20#include <sys/types.h>
21#include <linux/netlink.h>
22#include <linux/rtnetlink.h>
23
24#define LOG_TAG "Netd"
25#include <cutils/log.h>
26
27#include "NetdConstants.h"
28#include "NetlinkCommands.h"
29
30namespace android {
31namespace net {
32
33int openRtNetlinkSocket() {
34 int sock = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
35 if (sock == -1) {
36 return -errno;
37 }
38 if (connect(sock, reinterpret_cast<const sockaddr*>(&KERNEL_NLADDR),
39 sizeof(KERNEL_NLADDR)) == -1) {
40 return -errno;
41 }
42 return sock;
43}
44
45int recvNetlinkAck(int sock) {
46 struct {
47 nlmsghdr msg;
48 nlmsgerr err;
49 } response;
50
51 int ret = recv(sock, &response, sizeof(response), 0);
52
53 if (ret == -1) {
54 ret = -errno;
55 ALOGE("netlink recv failed (%s)", strerror(-ret));
56 return ret;
57 }
58
59 if (ret != sizeof(response)) {
60 ALOGE("bad netlink response message size (%d != %zu)", ret, sizeof(response));
61 return -EBADMSG;
62 }
63
64 return response.err.error; // Netlink errors are negative errno.
65}
66
67// Sends a netlink request and possibly expects an ack.
68// |iov| is an array of struct iovec that contains the netlink message payload.
69// The netlink header is generated by this function based on |action| and |flags|.
70// Returns -errno if there was an error or if the kernel reported an error.
71#ifdef __clang__
72#if __has_feature(address_sanitizer)
73__attribute__((optnone))
74#endif
75#endif
76WARN_UNUSED_RESULT int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen,
77 const NetlinkDumpCallback& callback) {
78 nlmsghdr nlmsg = {
79 .nlmsg_type = action,
80 .nlmsg_flags = flags,
81 };
82 iov[0].iov_base = &nlmsg;
83 iov[0].iov_len = sizeof(nlmsg);
84 for (int i = 0; i < iovlen; ++i) {
85 nlmsg.nlmsg_len += iov[i].iov_len;
86 }
87
88 int sock = openRtNetlinkSocket();
89 if (sock < 0) {
90 return sock;
91 }
92
93
94 int ret = 0;
95
96 if (writev(sock, iov, iovlen) == -1) {
97 ret = -errno;
98 ALOGE("netlink socket connect/writev failed (%s)", strerror(-ret));
99 close(sock);
100 return ret;
101 }
102
103 if (flags & NLM_F_ACK) {
104 ret = recvNetlinkAck(sock);
105 }
106
107 if ((flags & NLM_F_DUMP) && callback != nullptr) {
108 ret = processNetlinkDump(sock, callback);
109 }
110
111 close(sock);
112
113 return ret;
114}
115
116int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) {
117 return sendNetlinkRequest(action, flags, iov, iovlen, nullptr);
118}
119
120int processNetlinkDump(int sock, const NetlinkDumpCallback& callback) {
121 char buf[kNetlinkDumpBufferSize];
122
123 ssize_t bytesread;
124 do {
125 bytesread = read(sock, buf, sizeof(buf));
126
127 if (bytesread < 0) {
128 return -errno;
129 }
130
131 uint32_t len = bytesread;
132 for (nlmsghdr *nlh = reinterpret_cast<nlmsghdr *>(buf);
133 NLMSG_OK(nlh, len);
134 nlh = NLMSG_NEXT(nlh, len)) {
135 switch (nlh->nlmsg_type) {
136 case NLMSG_DONE:
137 callback(nullptr);
138 return 0;
139 case NLMSG_ERROR: {
140 nlmsgerr *err = reinterpret_cast<nlmsgerr *>(NLMSG_DATA(nlh));
141 return err->error;
142 }
143 default:
144 callback(nlh);
145 }
146 }
147 } while (bytesread > 0);
148
149 return 0;
150}
151
152} // namespace net
153} // namespace android