1 /*
2  * Copyright (c) 2023 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 "bus_center_decision_center.h"
17 
18 #include <stdbool.h>
19 #include <securec.h>
20 
21 #include "anonymizer.h"
22 #include "bus_center_manager.h"
23 #include "lnn_log.h"
24 #include "lnn_distributed_net_ledger.h"
25 #include "lnn_net_builder.h"
26 #include "softbus_adapter_mem.h"
27 #include "softbus_errcode.h"
28 #include "softbus_utils.h"
29 
30 #define HCI_ERR_BR_CONN_PAGE_TIMEOUT 0x04
31 #define HCI_ERR_BR_CONN_PEER_NOT_SUPORT_SDP_RECODE 0x54
32 #define HCI_ERR_BR_CONN_ACL_RECREATE 0x57
33 
34 #define BR_PAGETIMEOUT_OFFLINE_COUNT 3
35 #define BR_SDP_NOT_SUPORT_OFFLINE_COUNT 2
36 
37 typedef struct {
38     ListNode node;
39     ConnectOption option;
40     int32_t errorCode;
41     uint32_t count;
42 } ExceptionConnInfo;
43 
44 typedef struct {
45     SoftBusList *connections;
46     bool initFlag;
47 } ExceptionConnMgr;
48 
49 static ExceptionConnMgr g_exceptionConnMgr;
50 
LeaveSpecificBrNetwork(const char * addr)51 static void LeaveSpecificBrNetwork(const char *addr)
52 {
53     char networkId[NETWORK_ID_BUF_LEN] = { 0 };
54     if (LnnGetNetworkIdByBtMac(addr, networkId, sizeof(networkId)) != SOFTBUS_OK) {
55         LNN_LOGE(LNN_STATE, "networkId not found by addr");
56         return;
57     }
58 
59     int32_t ret = LnnRequestLeaveSpecific(networkId, CONNECTION_ADDR_BR);
60     if (ret != SOFTBUS_OK) {
61         LNN_LOGW(LNN_STATE, "leave br network failed, ret=%{public}d", ret);
62     }
63     LNN_LOGI(LNN_STATE, "leave br network finished");
64 }
65 
HandleBrConnectException(const ConnectOption * option,int32_t errorCode)66 static void HandleBrConnectException(const ConnectOption *option, int32_t errorCode)
67 {
68     if (errorCode != HCI_ERR_BR_CONN_PAGE_TIMEOUT && errorCode != HCI_ERR_BR_CONN_PEER_NOT_SUPORT_SDP_RECODE &&
69         errorCode != HCI_ERR_BR_CONN_ACL_RECREATE) {
70         return;
71     }
72     if (errorCode == HCI_ERR_BR_CONN_ACL_RECREATE) {
73         LeaveSpecificBrNetwork(option->brOption.brMac);
74         return;
75     }
76 
77     ExceptionConnInfo *target = NULL;
78     ExceptionConnInfo *it = NULL;
79     LIST_FOR_EACH_ENTRY(it, &g_exceptionConnMgr.connections->list, ExceptionConnInfo, node) {
80         if (StrCmpIgnoreCase(it->option.brOption.brMac, option->brOption.brMac) == 0 &&
81             it->errorCode == errorCode) {
82             target = it;
83             break;
84         }
85     }
86 
87     if (target != NULL) {
88         target->count++;
89         LNN_LOGD(LNN_STATE,
90             "exception connect info: errorCode=%{public}d, count=%{public}d", target->errorCode, target->count);
91         if ((target->errorCode == HCI_ERR_BR_CONN_PAGE_TIMEOUT && target->count >= BR_PAGETIMEOUT_OFFLINE_COUNT) ||
92             (target->errorCode == HCI_ERR_BR_CONN_PEER_NOT_SUPORT_SDP_RECODE &&
93             target->count >= BR_SDP_NOT_SUPORT_OFFLINE_COUNT)) {
94             LeaveSpecificBrNetwork(option->brOption.brMac);
95             ListDelete(&target->node);
96             SoftBusFree(target);
97             g_exceptionConnMgr.connections->cnt--;
98         }
99         return;
100     }
101 
102     ExceptionConnInfo *connInfo = SoftBusCalloc(sizeof(ExceptionConnInfo));
103     LNN_CHECK_AND_RETURN_LOGE(connInfo != NULL, LNN_STATE, "calloc br conn info failed");
104     if (strcpy_s(connInfo->option.brOption.brMac, BT_MAC_LEN, option->brOption.brMac) != EOK) {
105         LNN_LOGE(LNN_STATE, "copy address failed");
106         SoftBusFree(connInfo);
107         return;
108     }
109     ListInit(&connInfo->node);
110     connInfo->option.type = option->type;
111     connInfo->option.brOption.sideType = option->brOption.sideType;
112     connInfo->errorCode = errorCode;
113     connInfo->count = 1;
114 
115     LNN_LOGD(LNN_STATE, "exception connect info: errorCode=%{public}d, count=1", errorCode);
116     ListAdd(&g_exceptionConnMgr.connections->list, &connInfo->node);
117     g_exceptionConnMgr.connections->cnt++;
118 }
119 
ClearBrConnectException(const ConnectOption * option)120 static void ClearBrConnectException(const ConnectOption *option)
121 {
122     ExceptionConnInfo *it = NULL;
123     ExceptionConnInfo *next = NULL;
124     LIST_FOR_EACH_ENTRY_SAFE(it, next, &g_exceptionConnMgr.connections->list, ExceptionConnInfo, node) {
125         if (StrCmpIgnoreCase(it->option.brOption.brMac, option->brOption.brMac) == 0) {
126             ListDelete(&it->node);
127             SoftBusFree(it);
128             g_exceptionConnMgr.connections->cnt--;
129         }
130     }
131 }
132 
LnnDCReportConnectException(const ConnectOption * option,int32_t errorCode)133 void LnnDCReportConnectException(const ConnectOption *option, int32_t errorCode)
134 {
135     LNN_CHECK_AND_RETURN_LOGW(option != NULL, LNN_STATE, "option is NULL");
136     LNN_CHECK_AND_RETURN_LOGE(g_exceptionConnMgr.initFlag && g_exceptionConnMgr.connections != NULL,
137         LNN_STATE, "decision center not init yet");
138     SoftBusMutexLock(&g_exceptionConnMgr.connections->lock);
139     LNN_LOGI(LNN_STATE, "connType=%{public}d, errorCode=%{public}d", option->type, errorCode);
140     switch (option->type) {
141         case CONNECT_BR:
142             HandleBrConnectException(option, errorCode);
143             break;
144         default:
145             LNN_LOGW(LNN_STATE, "undefined connType=%{public}d", option->type);
146             break;
147     }
148     SoftBusMutexUnlock(&g_exceptionConnMgr.connections->lock);
149 }
150 
LnnDCClearConnectException(const ConnectOption * option)151 void LnnDCClearConnectException(const ConnectOption *option)
152 {
153     LNN_CHECK_AND_RETURN_LOGW(option != NULL, LNN_STATE, "option is NULL");
154     LNN_CHECK_AND_RETURN_LOGE(g_exceptionConnMgr.initFlag && g_exceptionConnMgr.connections != NULL,
155         LNN_STATE, "decision center not init yet");
156     SoftBusMutexLock(&g_exceptionConnMgr.connections->lock);
157     switch (option->type) {
158         case CONNECT_BR:
159             ClearBrConnectException(option);
160             break;
161         default:
162             LNN_LOGW(LNN_STATE, "undefined connType=%{public}d", option->type);
163             break;
164     }
165     SoftBusMutexUnlock(&g_exceptionConnMgr.connections->lock);
166 }
167 
LnnDCProcessOnlineState(bool isOnline,const NodeBasicInfo * info)168 void LnnDCProcessOnlineState(bool isOnline, const NodeBasicInfo *info)
169 {
170     LNN_CHECK_AND_RETURN_LOGW(info != NULL, LNN_STATE, " info is NULL");
171     char *anonyNetworkId = NULL;
172     Anonymize(info->networkId, &anonyNetworkId);
173     LNN_LOGI(LNN_STATE,
174         "onlineState=%{public}s, networkId=%{public}s", (isOnline ? "online" : "offline"), anonyNetworkId);
175     if (isOnline) {
176         LNN_LOGD(LNN_LEDGER, "ignore for online");
177         AnonymizeFree(anonyNetworkId);
178         return;
179     }
180 
181     NodeInfo nodeInfo = { 0 };
182     if (LnnGetRemoteNodeInfoById(info->networkId, CATEGORY_NETWORK_ID, &nodeInfo) != SOFTBUS_OK) {
183         LNN_LOGE(LNN_STATE, "can not get remote nodeinfo. networkId=%{public}s", anonyNetworkId);
184         AnonymizeFree(anonyNetworkId);
185         return;
186     }
187     AnonymizeFree(anonyNetworkId);
188     ConnectOption option = { 0 };
189     option.type = CONNECT_BR;
190     if (strcpy_s(option.brOption.brMac, BT_MAC_LEN, LnnGetBtMac(&nodeInfo)) == EOK) {
191         LnnDCClearConnectException(&option);
192     }
193 }
194 
InitDecisionCenter(void)195 int32_t InitDecisionCenter(void)
196 {
197     g_exceptionConnMgr.connections = CreateSoftBusList();
198     if (g_exceptionConnMgr.connections == NULL) {
199         LNN_LOGE(LNN_INIT, "creat exception conn mgr list failed");
200         g_exceptionConnMgr.initFlag = false;
201         return SOFTBUS_ERR;
202     }
203     g_exceptionConnMgr.initFlag = true;
204     LNN_LOGD(LNN_INIT, "init ok");
205     return SOFTBUS_OK;
206 }
207 
DeinitDecisionCenter(void)208 void DeinitDecisionCenter(void)
209 {
210     g_exceptionConnMgr.initFlag = false;
211     if (g_exceptionConnMgr.connections != NULL) {
212         DestroySoftBusList(g_exceptionConnMgr.connections);
213         g_exceptionConnMgr.connections = NULL;
214     }
215     LNN_LOGD(LNN_INIT, "deinit ok");
216 }