1 /*
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 #define LOG_TAG "NetlinkListener"
18
19 #include "NetlinkListener.h"
20
21 #include <sstream>
22 #include <vector>
23
24 #include <linux/netfilter/nfnetlink.h>
25
26 #include <log/log.h>
27 #include <netdutils/Misc.h>
28 #include <netdutils/Syscalls.h>
29
30 namespace android {
31 namespace net {
32
33 using netdutils::Fd;
34 using netdutils::Slice;
35 using netdutils::Status;
36 using netdutils::UniqueFd;
37 using netdutils::findWithDefault;
38 using netdutils::forEachNetlinkMessage;
39 using netdutils::makeSlice;
40 using netdutils::sSyscalls;
41 using netdutils::status::ok;
42 using netdutils::statusFromErrno;
43
44 namespace {
45
46 constexpr int kNetlinkMsgErrorType = (NFNL_SUBSYS_NONE << 8) | NLMSG_ERROR;
47
48 constexpr sockaddr_nl kKernelAddr = {
49 .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = 0,
50 };
51
__anona582d5ab0202(const nlmsghdr& nlmsg, const Slice) 52 const NetlinkListener::DispatchFn kDefaultDispatchFn = [](const nlmsghdr& nlmsg, const Slice) {
53 std::stringstream ss;
54 ss << nlmsg;
55 ALOGE("unhandled netlink message: %s", ss.str().c_str());
56 };
57
58 } // namespace
59
NetlinkListener(UniqueFd event,UniqueFd sock,const std::string & name)60 NetlinkListener::NetlinkListener(UniqueFd event, UniqueFd sock, const std::string& name)
61 : mEvent(std::move(event)), mSock(std::move(sock)), mThreadName(name) {
62 const auto rxErrorHandler = [](const nlmsghdr& nlmsg, const Slice msg) {
63 std::stringstream ss;
64 ss << nlmsg << " " << msg << " " << netdutils::toHex(msg, 32);
65 ALOGE("unhandled netlink message: %s", ss.str().c_str());
66 };
67 expectOk(NetlinkListener::subscribe(kNetlinkMsgErrorType, rxErrorHandler));
68
69 mErrorHandler = [& name = mThreadName](const int fd, const int err) {
70 ALOGE("Error on NetlinkListener(%s) fd=%d: %s", name.c_str(), fd, strerror(err));
71 };
72
73 // Start the thread
74 mWorker = std::thread([this]() { run().ignoreError(); });
75 }
76
~NetlinkListener()77 NetlinkListener::~NetlinkListener() {
78 const auto& sys = sSyscalls.get();
79 const uint64_t data = 1;
80 // eventfd should never enter an error state unexpectedly
81 expectOk(sys.write(mEvent, makeSlice(data)).status());
82 mWorker.join();
83 }
84
send(const Slice msg)85 Status NetlinkListener::send(const Slice msg) {
86 const auto& sys = sSyscalls.get();
87 ASSIGN_OR_RETURN(auto sent, sys.sendto(mSock, msg, 0, kKernelAddr));
88 if (sent != msg.size()) {
89 return statusFromErrno(EMSGSIZE, "unexpect message size");
90 }
91 return ok;
92 }
93
subscribe(uint16_t type,const DispatchFn & fn)94 Status NetlinkListener::subscribe(uint16_t type, const DispatchFn& fn) {
95 std::lock_guard guard(mMutex);
96 mDispatchMap[type] = fn;
97 return ok;
98 }
99
unsubscribe(uint16_t type)100 Status NetlinkListener::unsubscribe(uint16_t type) {
101 std::lock_guard guard(mMutex);
102 mDispatchMap.erase(type);
103 return ok;
104 }
105
registerSkErrorHandler(const SkErrorHandler & handler)106 void NetlinkListener::registerSkErrorHandler(const SkErrorHandler& handler) {
107 mErrorHandler = handler;
108 }
109
run()110 Status NetlinkListener::run() {
111 std::vector<char> rxbuf(4096);
112
113 const auto rxHandler = [this](const nlmsghdr& nlmsg, const Slice& buf) {
114 std::lock_guard guard(mMutex);
115 const auto& fn = findWithDefault(mDispatchMap, nlmsg.nlmsg_type, kDefaultDispatchFn);
116 fn(nlmsg, buf);
117 };
118
119 if (mThreadName.length() > 0) {
120 int ret = pthread_setname_np(pthread_self(), mThreadName.c_str());
121 if (ret) {
122 ALOGE("thread name set failed, name: %s, ret: %s", mThreadName.c_str(), strerror(ret));
123 }
124 }
125 const auto& sys = sSyscalls.get();
126 const std::array<Fd, 2> fds{{{mEvent}, {mSock}}};
127 const int events = POLLIN;
128 const double timeout = 3600;
129 while (true) {
130 ASSIGN_OR_RETURN(auto revents, sys.ppoll(fds, events, timeout));
131 // After mEvent becomes readable, we should stop servicing mSock and return
132 if (revents[0] & POLLIN) {
133 break;
134 }
135 if (revents[1] & (POLLIN|POLLERR)) {
136 auto rx = sys.recvfrom(mSock, makeSlice(rxbuf), 0);
137 int err = rx.status().code();
138 if (err) {
139 // Ignore errors. The only error we expect to see here is ENOBUFS, and there's
140 // nothing we can do about that. The recvfrom above will already have cleared the
141 // error indication and ensured we won't get EPOLLERR again.
142 // TODO: Consider using NETLINK_NO_ENOBUFS.
143 mErrorHandler(((Fd) mSock).get(), err);
144 continue;
145 }
146 forEachNetlinkMessage(rx.value(), rxHandler);
147 }
148 }
149 return ok;
150 }
151
152 } // namespace net
153 } // namespace android
154