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)53 bool CreateNetlinkDistributor(int32_t netlinkType, const DistributorParam ¶m)
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",
66 netlinkType, 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);
93 return true;
94 }
95 } // namespace
96
97 std::shared_ptr<std::vector<sptr<NetsysNative::INotifyCallback>>> NetlinkManager::callbacks_ =
98 std::make_shared<std::vector<sptr<NetsysNative::INotifyCallback>>>();
NetlinkManager()99 NetlinkManager::NetlinkManager()
100 {
101 for (const auto &it : distributorParamList_) {
102 CreateNetlinkDistributor(it.first, it.second);
103 }
104 if (callbacks_ == nullptr) {
105 callbacks_ = std::make_shared<std::vector<sptr<NetsysNative::INotifyCallback>>>();
106 }
107 }
108
~NetlinkManager()109 NetlinkManager::~NetlinkManager()
110 {
111 callbacks_->clear();
112 callbacks_ = nullptr;
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 if (callback == nullptr) {
147 NETNATIVE_LOGE("callback is nullptr");
148 return NetlinkResult::ERR_NULL_PTR;
149 }
150 for (const auto &cb : *callbacks_) {
151 if (cb == callback) {
152 NETNATIVE_LOGI("callback is already registered");
153 return NetlinkResult::OK;
154 }
155 }
156 callbacks_->push_back(callback);
157 NETNATIVE_LOGI("callback is registered successfully current size is %{public}zu", callbacks_->size());
158 return NetlinkResult::OK;
159 }
160
UnregisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)161 int32_t NetlinkManager::UnregisterNetlinkCallback(sptr<NetsysNative::INotifyCallback> callback)
162 {
163 if (callback == nullptr) {
164 NETNATIVE_LOGE("callback is nullptr");
165 return NetlinkResult::ERR_NULL_PTR;
166 }
167
168 for (auto it = callbacks_->begin(); it != callbacks_->end(); ++it) {
169 if (*it == callback) {
170 callbacks_->erase(it);
171 NETNATIVE_LOGI("callback is unregistered successfully");
172 return NetlinkResult::OK;
173 }
174 }
175 NETNATIVE_LOGI("callback has not registered current callback number is %{public}zu", callbacks_->size());
176 return NetlinkResult::ERR_INVALID_PARAM;
177 }
178 } // namespace nmd
179 } // namespace OHOS
180