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 }