blob: 91149c0160af7ec4a89853c8754784cda3bfe5a7 [file] [log] [blame]
Tomasz Wasilczyk87329672019-07-12 11:43:00 -07001/*
2 * Copyright (C) 2019 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
chrisweir3fb244a2020-06-29 13:05:17 -070017#include <libnetdevice/NetlinkSocket.h>
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070018
Tomasz Wasilczyka9872732020-06-02 18:03:27 -070019#include <libnetdevice/printer.h>
20
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070021#include <android-base/logging.h>
22
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -080023namespace android::netdevice {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070024
Tomasz Wasilczyka9872732020-06-02 18:03:27 -070025/**
26 * Print all outbound/inbound Netlink messages.
27 */
28static constexpr bool kSuperVerbose = false;
29
chrisweir06c2c0d2020-06-18 16:06:40 -070030NetlinkSocket::NetlinkSocket(int protocol, unsigned int pid, uint32_t groups)
31 : mProtocol(protocol) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070032 mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
33 if (!mFd.ok()) {
chrisweir1173a722020-02-26 14:39:56 -080034 PLOG(ERROR) << "Can't open Netlink socket";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070035 mFailed = true;
36 return;
37 }
38
chrisweir06c2c0d2020-06-18 16:06:40 -070039 sockaddr_nl sa = {};
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070040 sa.nl_family = AF_NETLINK;
chrisweir06c2c0d2020-06-18 16:06:40 -070041 sa.nl_pid = pid;
42 sa.nl_groups = groups;
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070043
chrisweir06c2c0d2020-06-18 16:06:40 -070044 if (bind(mFd.get(), reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) < 0) {
chrisweir1173a722020-02-26 14:39:56 -080045 PLOG(ERROR) << "Can't bind Netlink socket";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070046 mFd.reset();
47 mFailed = true;
48 }
49}
50
chrisweir06c2c0d2020-06-18 16:06:40 -070051bool NetlinkSocket::send(nlmsghdr* nlmsg, size_t totalLen) {
Tomasz Wasilczyka9872732020-06-02 18:03:27 -070052 if constexpr (kSuperVerbose) {
53 nlmsg->nlmsg_seq = mSeq;
chrisweir06c2c0d2020-06-18 16:06:40 -070054 LOG(VERBOSE) << (mFailed ? "(not) " : "")
55 << "sending Netlink message: " << toString({nlmsg, totalLen}, mProtocol);
Tomasz Wasilczyka9872732020-06-02 18:03:27 -070056 }
57
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070058 if (mFailed) return false;
59
60 nlmsg->nlmsg_pid = 0; // kernel
61 nlmsg->nlmsg_seq = mSeq++;
62 nlmsg->nlmsg_flags |= NLM_F_ACK;
63
chrisweir06c2c0d2020-06-18 16:06:40 -070064 iovec iov = {nlmsg, nlmsg->nlmsg_len};
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070065
chrisweir06c2c0d2020-06-18 16:06:40 -070066 sockaddr_nl sa = {};
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070067 sa.nl_family = AF_NETLINK;
68
chrisweir06c2c0d2020-06-18 16:06:40 -070069 msghdr msg = {};
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070070 msg.msg_name = &sa;
71 msg.msg_namelen = sizeof(sa);
72 msg.msg_iov = &iov;
73 msg.msg_iovlen = 1;
74
75 if (sendmsg(mFd.get(), &msg, 0) < 0) {
chrisweir1173a722020-02-26 14:39:56 -080076 PLOG(ERROR) << "Can't send Netlink message";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070077 return false;
78 }
79 return true;
80}
81
chrisweir06c2c0d2020-06-18 16:06:40 -070082bool NetlinkSocket::send(const nlbuf<nlmsghdr>& msg, const sockaddr_nl& sa) {
83 if constexpr (kSuperVerbose) {
84 LOG(VERBOSE) << (mFailed ? "(not) " : "")
85 << "sending Netlink message: " << toString(msg, mProtocol);
86 }
87
88 if (mFailed) return false;
89 const auto rawMsg = msg.getRaw();
90 const auto bytesSent = sendto(mFd.get(), rawMsg.ptr(), rawMsg.len(), 0,
91 reinterpret_cast<const sockaddr*>(&sa), sizeof(sa));
92 if (bytesSent < 0) {
93 PLOG(ERROR) << "Can't send Netlink message";
94 return false;
95 }
96 return true;
97}
98
99std::optional<nlbuf<nlmsghdr>> NetlinkSocket::receive(void* buf, size_t bufLen) {
100 sockaddr_nl sa = {};
101 return receive(buf, bufLen, sa);
102}
103
104std::optional<nlbuf<nlmsghdr>> NetlinkSocket::receive(void* buf, size_t bufLen, sockaddr_nl& sa) {
105 if (mFailed) return std::nullopt;
106
107 socklen_t saLen = sizeof(sa);
108 if (bufLen == 0) {
109 LOG(ERROR) << "Receive buffer has zero size!";
110 return std::nullopt;
111 }
112 const auto bytesReceived =
113 recvfrom(mFd.get(), buf, bufLen, MSG_TRUNC, reinterpret_cast<sockaddr*>(&sa), &saLen);
114 if (bytesReceived <= 0) {
115 PLOG(ERROR) << "Failed to receive Netlink message";
116 return std::nullopt;
117 } else if (unsigned(bytesReceived) > bufLen) {
118 PLOG(ERROR) << "Received data larger than the receive buffer! " << bytesReceived << " > "
119 << bufLen;
120 return std::nullopt;
121 }
122
123 nlbuf<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(buf), bytesReceived);
124 if constexpr (kSuperVerbose) {
125 LOG(VERBOSE) << "received " << toString(msg, mProtocol);
126 }
127 return msg;
128}
129
130/* TODO(161389935): Migrate receiveAck to use nlmsg<> internally. Possibly reuse
131 * NetlinkSocket::receive(). */
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700132bool NetlinkSocket::receiveAck() {
133 if (mFailed) return false;
134
135 char buf[8192];
136
chrisweir06c2c0d2020-06-18 16:06:40 -0700137 sockaddr_nl sa;
138 iovec iov = {buf, sizeof(buf)};
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700139
chrisweir06c2c0d2020-06-18 16:06:40 -0700140 msghdr msg = {};
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700141 msg.msg_name = &sa;
142 msg.msg_namelen = sizeof(sa);
143 msg.msg_iov = &iov;
144 msg.msg_iovlen = 1;
145
146 const ssize_t status = recvmsg(mFd.get(), &msg, 0);
147 if (status < 0) {
chrisweir1173a722020-02-26 14:39:56 -0800148 PLOG(ERROR) << "Failed to receive Netlink message";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700149 return false;
150 }
151 size_t remainingLen = status;
152
153 if (msg.msg_flags & MSG_TRUNC) {
154 LOG(ERROR) << "Failed to receive Netlink message: truncated";
155 return false;
156 }
157
chrisweir06c2c0d2020-06-18 16:06:40 -0700158 for (auto nlmsg = reinterpret_cast<nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700159 nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
Tomasz Wasilczyka9872732020-06-02 18:03:27 -0700160 if constexpr (kSuperVerbose) {
161 LOG(VERBOSE) << "received Netlink response: "
chrisweir06c2c0d2020-06-18 16:06:40 -0700162 << toString({nlmsg, nlmsg->nlmsg_len}, mProtocol);
Tomasz Wasilczyka9872732020-06-02 18:03:27 -0700163 }
164
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700165 // We're looking for error/ack message only, ignoring others.
166 if (nlmsg->nlmsg_type != NLMSG_ERROR) {
167 LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
168 continue;
169 }
170
171 // Found error/ack message, return status.
chrisweir06c2c0d2020-06-18 16:06:40 -0700172 const auto nlerr = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(nlmsg));
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700173 if (nlerr->error != 0) {
Tomasz Wasilczyk1accab92020-07-01 08:08:43 -0700174 LOG(ERROR) << "Received Netlink error message: " << strerror(-nlerr->error);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700175 return false;
176 }
177 return true;
178 }
179 // Couldn't find any error/ack messages.
180 return false;
181}
182
chrisweir06c2c0d2020-06-18 16:06:40 -0700183std::optional<unsigned int> NetlinkSocket::getSocketPid() {
184 sockaddr_nl sa = {};
185 socklen_t sasize = sizeof(sa);
186 if (getsockname(mFd.get(), reinterpret_cast<sockaddr*>(&sa), &sasize) < 0) {
187 PLOG(ERROR) << "Failed to getsockname() for netlink_fd!";
188 return std::nullopt;
189 }
190 return sa.nl_pid;
191}
192
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -0800193} // namespace android::netdevice