1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "netlink_manager.h"
17
18 #include <cerrno>
19 #include <linux/netlink.h>
20 #include <linux/rtnetlink.h>
21 #include <map>
22 #include <mutex>
23 #include <sys/socket.h>
24 #include <unistd.h>
25
26 #include "netlink_define.h"
27 #include "netnative_log_wrapper.h"
28 #include "wrapper_distributor.h"
29
30 namespace OHOS {
31 namespace nmd {
32 using namespace NetlinkDefine;
33 namespace {
34 constexpr int32_t NFLOG_QUOTA_GROUP = 1;
35 constexpr int32_t UEVENT_GROUP = 0xffffffff;
36 struct DistributorParam {
37 int32_t groups;
38 int32_t format;
39 bool flag;
40 };
41
42 const std::map<int32_t, DistributorParam> distributorParamList_ = {
43 {NETLINK_KOBJECT_UEVENT, {UEVENT_GROUP, NETLINK_FORMAT_ASCII, false}},
44 {NETLINK_ROUTE,
45 {RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE |
46 (1 << (RTNLGRP_ND_USEROPT - 1)),
47 NETLINK_FORMAT_BINARY, false}},
48 {NETLINK_NFLOG, {NFLOG_QUOTA_GROUP, NETLINK_FORMAT_BINARY, false}},
49 {NETLINK_NETFILTER, {0, NETLINK_FORMAT_BINARY_UNICAST, true}}};
50
51 std::map<int32_t, std::unique_ptr<WrapperDistributor>> distributorMap_;
52
CreateNetlinkDistributor(int32_t netlinkType,const DistributorParam & param,std::mutex & externMutex)53 bool CreateNetlinkDistributor(int32_t netlinkType, const DistributorParam ¶m, std::mutex& externMutex)
54 {
55 sockaddr_nl sockAddr;
56 int32_t size = BUFFER_SIZE;
57 int32_t on = 1;
58 int32_t socketFd;
59
60 sockAddr.nl_family = AF_NETLINK;
61 sockAddr.nl_pid = 0;
62 sockAddr.nl_groups = param.groups;
63
64 if ((socketFd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, netlinkType)) < 0) {
65 NETNATIVE_LOGE("Creat socket for family failed NetLinkType is %{public}d: %{public}s = %{public}d", netlinkType,
66 strerror(errno), errno);
67 return false;
68 }
69
70 if (setsockopt(socketFd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0 &&
71 setsockopt(socketFd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0) {
72 NETNATIVE_LOGE("Set buffer for revieve msg failed the error is : %{public}d, EMSG: %{public}s", errno,
73 strerror(errno));
74 close(socketFd);
75 return false;
76 }
77
78 if (setsockopt(socketFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
79 NETNATIVE_LOGE("Uevent socket SO_PASSCRED set failed dump for this: %{public}d, EMSG: %{public}s", errno,
80 strerror(errno));
81 close(socketFd);
82 return false;
83 }
84
85 if (bind(socketFd, reinterpret_cast<sockaddr *>(&sockAddr), sizeof(sockAddr)) < 0) {
86 NETNATIVE_LOGE("Bind netlink socket failed dumps is this : %{public}d, EMSG: %{public}s", errno,
87 strerror(errno));
88 close(socketFd);
89 return false;
90 }
91 NETNATIVE_LOGI("CreateNetlinkDistributor netlinkType: %{public}d, socketFd: %{public}d", netlinkType, socketFd);
92 distributorMap_[netlinkType] = std::make_unique<WrapperDistributor>(socketFd, param.format, externMutex);
93 return true;
94 }
95 } // namespace
96
NetlinkManager()97 NetlinkManager::NetlinkManager()
98 {
99 for (const auto &it : distributorParamList_) {
100 CreateNetlinkDistributor(it.first, it.second, linkCallbackMutex_);
101 }
102 if (callbacks_ == nullptr) {
103 callbacks_ = std::make_shared<std::vector<sptr<NetsysNative::INotifyCallback>>>();
104 }
105 }
106
~NetlinkManager()107 NetlinkManager::~NetlinkManager()
108 {
109 if (callbacks_ != nullptr) {
110 callbacks_->clear();
111 callbacks_ = nullptr;
112 }
113 }
114
StartListener()115 int32_t NetlinkManager::StartListener()
116 {
117 for (auto &it : distributorMap_) {
118 if (it.second == nullptr) {
119 continue;
120 }
121 it.second->RegisterNetlinkCallbacks(callbacks_);
122 if (it.second->Start() != 0) {
123 NETNATIVE_LOGE("Start netlink listener failed");
124 return NetlinkResult::ERROR;
125 }
126 }
127 return NetlinkResult::OK;
128 }
129
StopListener()130 int32_t NetlinkManager::StopListener()
131 {
132 for (auto &it : distributorMap_) {
133 if (it.second == nullptr) {
134 continue;
135 }
136 if (it.second->Stop() != 0) {
137 NETNATIVE_LOGE("Stop netlink listener failed");
138 return NetlinkResult::ERROR;
139 }
140 }
141 return NetlinkResult::OK;
142 }
143
RegisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)144 int32_t NetlinkManager::RegisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)
145 {
146 std::lock_guard<std::mutex> lock(linkCallbackMutex_);
147 if (callback == nullptr) {
148 NETNATIVE_LOGE("callback is nullptr");
149 return NetlinkResult::ERR_NULL_PTR;
150 }
151 for (const auto &cb : *callbacks_) {
152 if (cb == callback) {
153 NETNATIVE_LOGI("callback is already registered");
154 return NetlinkResult::OK;
155 }
156 }
157 callbacks_->push_back(callback);
158 NETNATIVE_LOGI("callback is registered successfully current size is %{public}zu", callbacks_->size());
159 return NetlinkResult::OK;
160 }
161
UnregisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)162 int32_t NetlinkManager::UnregisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)
163 {
164 std::lock_guard<std::mutex> lock(linkCallbackMutex_);
165 if (callback == nullptr) {
166 NETNATIVE_LOGE("callback is nullptr");
167 return NetlinkResult::ERR_NULL_PTR;
168 }
169 for (auto it = callbacks_->begin(); it != callbacks_->end(); ++it) {
170 if (*it == callback) {
171 callbacks_->erase(it);
172 NETNATIVE_LOGI("callback is unregistered successfully");
173 return NetlinkResult::OK;
174 }
175 }
176 NETNATIVE_LOGI("callback has not registered current callback number is %{public}zu", callbacks_->size());
177 return NetlinkResult::ERR_INVALID_PARAM;
178 }
179 } // namespace nmd
180 } // namespace OHOS
181