blob: 86442f2eec59927ee22dcb760d3fdef8dae398da [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
17#include "NetlinkSocket.h"
18
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
30NetlinkSocket::NetlinkSocket(int protocol) : mProtocol(protocol) {
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070031 mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
32 if (!mFd.ok()) {
chrisweir1173a722020-02-26 14:39:56 -080033 PLOG(ERROR) << "Can't open Netlink socket";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070034 mFailed = true;
35 return;
36 }
37
38 struct sockaddr_nl sa = {};
39 sa.nl_family = AF_NETLINK;
40
41 if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
chrisweir1173a722020-02-26 14:39:56 -080042 PLOG(ERROR) << "Can't bind Netlink socket";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070043 mFd.reset();
44 mFailed = true;
45 }
46}
47
Tomasz Wasilczyka9872732020-06-02 18:03:27 -070048bool NetlinkSocket::send(struct nlmsghdr* nlmsg, size_t totalLen) {
49 if constexpr (kSuperVerbose) {
50 nlmsg->nlmsg_seq = mSeq;
51 LOG(VERBOSE) << (mFailed ? "(not)" : "")
52 << "sending Netlink message: " << toString(nlmsg, totalLen, mProtocol);
53 }
54
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070055 if (mFailed) return false;
56
57 nlmsg->nlmsg_pid = 0; // kernel
58 nlmsg->nlmsg_seq = mSeq++;
59 nlmsg->nlmsg_flags |= NLM_F_ACK;
60
61 struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
62
63 struct sockaddr_nl sa = {};
64 sa.nl_family = AF_NETLINK;
65
66 struct msghdr msg = {};
67 msg.msg_name = &sa;
68 msg.msg_namelen = sizeof(sa);
69 msg.msg_iov = &iov;
70 msg.msg_iovlen = 1;
71
72 if (sendmsg(mFd.get(), &msg, 0) < 0) {
chrisweir1173a722020-02-26 14:39:56 -080073 PLOG(ERROR) << "Can't send Netlink message";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070074 return false;
75 }
76 return true;
77}
78
79bool NetlinkSocket::receiveAck() {
80 if (mFailed) return false;
81
82 char buf[8192];
83
84 struct sockaddr_nl sa;
85 struct iovec iov = {buf, sizeof(buf)};
86
87 struct msghdr msg = {};
88 msg.msg_name = &sa;
89 msg.msg_namelen = sizeof(sa);
90 msg.msg_iov = &iov;
91 msg.msg_iovlen = 1;
92
93 const ssize_t status = recvmsg(mFd.get(), &msg, 0);
94 if (status < 0) {
chrisweir1173a722020-02-26 14:39:56 -080095 PLOG(ERROR) << "Failed to receive Netlink message";
Tomasz Wasilczyk87329672019-07-12 11:43:00 -070096 return false;
97 }
98 size_t remainingLen = status;
99
100 if (msg.msg_flags & MSG_TRUNC) {
101 LOG(ERROR) << "Failed to receive Netlink message: truncated";
102 return false;
103 }
104
105 for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
106 nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
Tomasz Wasilczyka9872732020-06-02 18:03:27 -0700107 if constexpr (kSuperVerbose) {
108 LOG(VERBOSE) << "received Netlink response: "
109 << toString(nlmsg, sizeof(buf), mProtocol);
110 }
111
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700112 // We're looking for error/ack message only, ignoring others.
113 if (nlmsg->nlmsg_type != NLMSG_ERROR) {
114 LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
115 continue;
116 }
117
118 // Found error/ack message, return status.
119 auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
120 if (nlerr->error != 0) {
Tomasz Wasilczyk1accab92020-07-01 08:08:43 -0700121 LOG(ERROR) << "Received Netlink error message: " << strerror(-nlerr->error);
Tomasz Wasilczyk87329672019-07-12 11:43:00 -0700122 return false;
123 }
124 return true;
125 }
126 // Couldn't find any error/ack messages.
127 return false;
128}
129
Tomasz Wasilczyk55f21932019-12-20 09:20:24 -0800130} // namespace android::netdevice