1 /*
2  * Copyright (c) 2024 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 "bpf_ring_buffer.h"
17 #include "net_policy_client.h"
18 #include "libbpf.h"
19 #include "ffrt.h"
20 #include "ffrt_inner.h"
21 
22 namespace OHOS::NetManagerStandard {
23 namespace {
24     const int RING_BUFFER_POLL_TIME_OUT_MS = -1;
25 }
26 bool NetsysBpfRingBuffer::existThread_ = true;
27 
BpfMapPathNameToU64(const std::string & pathName)28 uint64_t NetsysBpfRingBuffer::BpfMapPathNameToU64(const std::string &pathName)
29 {
30     return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pathName.c_str()));
31 }
32 
BpfSyscall(int32_t cmd,const bpf_attr & attr)33 int32_t NetsysBpfRingBuffer::BpfSyscall(int32_t cmd, const bpf_attr &attr)
34 {
35     return static_cast<int32_t>(syscall(__NR_bpf, cmd, &attr, sizeof(attr)));
36 }
37 
GetRingbufFd(const std::string & path,uint32_t fileFlags)38 int NetsysBpfRingBuffer::GetRingbufFd(const std::string &path, uint32_t fileFlags)
39 {
40     bpf_attr bpfAttr{};
41     memset_s(&bpfAttr, sizeof(bpfAttr), 0, sizeof(bpfAttr));
42     bpfAttr.pathname = BpfMapPathNameToU64(path);
43     bpfAttr.file_flags = fileFlags;
44     return BpfSyscall(BPF_OBJ_GET, bpfAttr);
45 }
46 
HandleNetworkPolicyEventCallback(void * ctx,void * data,size_t data_sz)47 int NetsysBpfRingBuffer::HandleNetworkPolicyEventCallback(void *ctx, void *data, size_t data_sz)
48 {
49     NETNATIVE_LOG_D("HandleNetworkPolicyEventCallback enter");
50     int32_t *e = (int32_t*)data;
51 
52     if (NetPolicyClient::GetInstance().NotifyNetAccessPolicyDiag(*e) != NETMANAGER_SUCCESS) {
53         NETNATIVE_LOGE("Notify to diag fail");
54         return RING_BUFFER_ERR_INTERNAL;
55     }
56 
57     return RING_BUFFER_ERR_NONE;
58 }
59 
ListenRingBufferThread(void)60 void NetsysBpfRingBuffer::ListenRingBufferThread(void)
61 {
62     auto ringbufFd = GetRingbufFd(RING_BUFFER_MAP_PATH, 0);
63     if (ringbufFd > 0) {
64         struct ring_buffer *rb = NULL;
65         int err = 0;
66         /* Set up ring buffer polling */
67         rb = ring_buffer__new(ringbufFd, HandleNetworkPolicyEventCallback, NULL, NULL);
68         if (!rb) {
69             err = -1;
70             NETNATIVE_LOGE("Bpf ring buffer new fail");
71             return;
72         }
73 
74         /* Process events */
75         while (existThread_) {
76             ffrt::sync_io(ringbufFd);
77             err = ring_buffer__poll(rb, RING_BUFFER_POLL_TIME_OUT_MS);
78             if (err < 0) {
79                 NETNATIVE_LOGE("Bpf ring buffer poll fail, err: %{public}d, errno: %{public}d", err, errno);
80                 break;
81             }
82         }
83 
84         ring_buffer__free(rb);
85     }
86 
87     NETNATIVE_LOGE("Could not get bpf ring buffer map");
88     return;
89 }
90 
ListenNetworkAccessPolicyEvent(void)91 void NetsysBpfRingBuffer::ListenNetworkAccessPolicyEvent(void)
92 {
93     ffrt::submit(ListenRingBufferThread, {}, {}, ffrt::task_attr().name("ListenRingBufferThread"));
94 }
95 
ExistRingBufferPoll(void)96 void NetsysBpfRingBuffer::ExistRingBufferPoll(void)
97 {
98     existThread_ = false;
99 }
100 }
101