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