1 /*
2 * Copyright (c) 2021 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 "p2plink_channel_freq.h"
17
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <time.h>
21
22 #include "securec.h"
23 #include "softbus_adapter_mem.h"
24 #include "softbus_errcode.h"
25 #include "softbus_log.h"
26
27 #define MAX_CHANNEL_ITEM 165
28 #define INVALID_5G_CHANNEL 165
29
30 #define FREQUENCY_2G_FIRST 2412
31 #define FREQUENCY_2G_LAST 2472
32 #define FREQUENCY_5G_FIRST 5170
33 #define FREQUENCY_5G_LAST 5825
34 #define CHANNEL_2G_FIRST 1
35 #define CHANNEL_2G_LAST 13
36 #define CHANNEL_5G_FIRST 34
37 #define CHANNEL_5G_LAST 165
38 #define FREQUENCY_STEP 5
39 #define CHANNEL_INVALID (-1)
40 #define FREQUENCY_INVALID (-1)
41
P2plinkChannelListToString(const P2pLink5GList * channelList,char * channelString,int32_t len)42 int32_t P2plinkChannelListToString(const P2pLink5GList *channelList, char *channelString, int32_t len)
43 {
44 if ((channelList == NULL) || (channelList->num == 0)) {
45 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_DBG, "channelList is null.");
46 return SOFTBUS_OK;
47 }
48
49 if (channelString == NULL) {
50 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "%s:invalid param.", __func__);
51 return SOFTBUS_INVALID_PARAM;
52 }
53
54 int32_t ret = sprintf_s(channelString, len, "%d", channelList->chans[0]);
55 if (ret == -1) {
56 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "sprintf_s failed, errno = %d.", errno);
57 return SOFTBUS_MEM_ERR;
58 }
59
60 for (int32_t i = 1; i < channelList->num; i++) {
61 int32_t writeRet = sprintf_s(channelString + ret, len - ret, "##%d", channelList->chans[i]);
62 if (writeRet == -1) {
63 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "sprintf_s failed, errno = %d.", errno);
64 return SOFTBUS_MEM_ERR;
65 }
66 ret += writeRet;
67 }
68
69 return SOFTBUS_OK;
70 }
71
P2pLinkParseItemDataByDelimit(char * srcStr,const char * delimit,char * list[],int32_t num,int32_t * outNum)72 void P2pLinkParseItemDataByDelimit(char *srcStr, const char *delimit, char *list[], int32_t num, int32_t *outNum)
73 {
74 // srcStr will be cut.
75 if (srcStr == NULL || delimit == NULL || list == NULL || outNum == NULL || num == 0) {
76 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "%s:invalid param.", __func__);
77 return;
78 }
79
80 char *itemStr = NULL;
81 char *saveItemPtr = NULL;
82 itemStr = strtok_s(srcStr, delimit, &saveItemPtr);
83 int32_t index = 0;
84 while (itemStr != NULL) {
85 if (index >= num) {
86 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_DBG, "over max input num, index = %d, max num = %d.", index, num);
87 index++;
88 break;
89 }
90 list[index++] = itemStr;
91 itemStr = strtok_s(NULL, delimit, &saveItemPtr);
92 }
93
94 *outNum = index;
95 }
96
97 // The caller needs to free memory
StringToChannelList(const char * channelString)98 static P2pLink5GList *StringToChannelList(const char *channelString)
99 {
100 if (channelString == NULL || strlen(channelString) == 0) {
101 return NULL;
102 }
103
104 char *list[MAX_CHANNEL_ITEM] = {0};
105 int32_t num;
106 char channelStringClone[CHAN_LIST_LEN] = {0};
107 if (strcpy_s(channelStringClone, sizeof(channelStringClone), channelString) != EOK) {
108 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "strcpy_s failed, errno = %d.", errno);
109 return NULL;
110 }
111 P2pLinkParseItemDataByDelimit(channelStringClone, "##", list, MAX_CHANNEL_ITEM, &num);
112 if (num == 0) {
113 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "parse channel string failed.");
114 return NULL;
115 }
116
117 P2pLink5GList *channelList = SoftBusCalloc(sizeof(P2pLink5GList) + sizeof(int32_t) * num);
118 if (channelList == NULL) {
119 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "calloc failed.");
120 return NULL;
121 }
122
123 channelList->num = num;
124 for (int32_t i = 0; i < num; i++) {
125 channelList->chans[i] = atoi(list[i]);
126 }
127
128 return channelList;
129 }
130
GetChannelByFreq(int32_t freq)131 static int32_t GetChannelByFreq(int32_t freq)
132 {
133 if (freq >= FREQUENCY_2G_FIRST && freq <= FREQUENCY_2G_LAST) {
134 return ((freq - FREQUENCY_2G_FIRST) / FREQUENCY_STEP) + CHANNEL_2G_FIRST;
135 } else if (freq >= FREQUENCY_5G_FIRST && freq <= FREQUENCY_5G_LAST) {
136 return ((freq - FREQUENCY_5G_FIRST) / FREQUENCY_STEP) + CHANNEL_5G_FIRST;
137 } else {
138 return CHANNEL_INVALID;
139 }
140 }
141
Is2GBand(int32_t freq)142 static bool Is2GBand(int32_t freq)
143 {
144 if (freq >= FREQUENCY_2G_FIRST && freq <= FREQUENCY_2G_LAST) {
145 return true;
146 }
147 return false;
148 }
149
IsInChannelList(int32_t channelItem,const P2pLink5GList * channelList)150 static bool IsInChannelList(int32_t channelItem, const P2pLink5GList *channelList)
151 {
152 if (channelList == NULL || channelList->num == 0) {
153 return false;
154 }
155
156 for (int32_t i = 0; i < channelList->num; i++) {
157 if (channelItem == channelList->chans[i]) {
158 return true;
159 }
160 }
161
162 return false;
163 }
164
P2pLinkUpateAndGetStationFreq(const P2pLink5GList * channelList)165 int32_t P2pLinkUpateAndGetStationFreq(const P2pLink5GList *channelList)
166 {
167 int32_t freq = P2pLinkGetFrequency();
168 if (freq < FREQUENCY_2G_FIRST) {
169 return FREQUENCY_INVALID;
170 }
171 int32_t channel = GetChannelByFreq(freq);
172 if (freq > FREQUENCY_2G_LAST && !IsInChannelList(channel, channelList)) {
173 freq = FREQUENCY_INVALID;
174 }
175
176 return freq;
177 }
178
GetFreqByChannel(int32_t channel)179 static int32_t GetFreqByChannel(int32_t channel)
180 {
181 if (channel >= CHANNEL_2G_FIRST && channel <= CHANNEL_2G_LAST) {
182 return (channel - CHANNEL_2G_FIRST) * FREQUENCY_STEP + FREQUENCY_2G_FIRST;
183 } else if (channel >= CHANNEL_5G_FIRST && channel <= CHANNEL_5G_LAST) {
184 return (channel - CHANNEL_5G_FIRST) * FREQUENCY_STEP + FREQUENCY_5G_FIRST;
185 }
186 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "channel to freq, channel = %d.", channel);
187 return FREQUENCY_INVALID;
188 }
189
GenerateFrequency(const P2pLink5GList * channelList,const P2pLink5GList * gcChannelList,const P2pLink5GList * gcScoreList)190 static int32_t GenerateFrequency(const P2pLink5GList *channelList, const P2pLink5GList *gcChannelList,
191 const P2pLink5GList *gcScoreList)
192 {
193 (void)gcScoreList;
194 if (channelList == NULL || channelList->num <= 0) {
195 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_DBG, "local 5g channel list is null.");
196 return FREQUENCY_INVALID;
197 }
198
199 P2pLink5GList *result = (P2pLink5GList *)SoftBusCalloc(sizeof(P2pLink5GList) + sizeof(int32_t) * channelList->num);
200 if (result == NULL) {
201 return FREQUENCY_INVALID;
202 }
203 result->num = 0;
204 for (int32_t i = 0; i < channelList->num; i++) {
205 if (channelList->chans[i] == INVALID_5G_CHANNEL) {
206 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_DBG, "can not use 5g channel 165.");
207 continue;
208 }
209 if (IsInChannelList(channelList->chans[i], gcChannelList)) {
210 result->chans[result->num] = channelList->chans[i];
211 result->num++;
212 }
213 }
214 if (result->num == 0) {
215 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_DBG, "can not use 5G channel.");
216 SoftBusFree(result);
217 return FREQUENCY_INVALID;
218 }
219 int32_t bestFreq = GetFreqByChannel(result->chans[0]);
220 // not suppot local channel scores, so don't caculate local channel and peer channel scores
221 SoftBusFree(result);
222 return bestFreq;
223 }
224
ChoseChannel5gFreq(const GcInfo * gc,const P2pLink5GList * channelList,const P2pLink5GList * gcChannelList,int32_t localStationFreq,int32_t gcStationFreq)225 static int32_t ChoseChannel5gFreq(const GcInfo *gc, const P2pLink5GList *channelList,
226 const P2pLink5GList *gcChannelList, int32_t localStationFreq, int32_t gcStationFreq)
227 {
228 if (gcChannelList != NULL || channelList != NULL) {
229 int32_t localChannel = GetChannelByFreq(localStationFreq);
230 if (IsInChannelList(localChannel, channelList) && IsInChannelList(localChannel, gcChannelList)) {
231 return localStationFreq;
232 }
233
234 int32_t gcChannel = GetChannelByFreq(gcStationFreq);
235 if (IsInChannelList(gcChannel, channelList) && IsInChannelList(gcChannel, gcChannelList)) {
236 return gcStationFreq;
237 }
238
239 /* channel score will be supported soon. */
240 int32_t freq = GenerateFrequency(channelList, gcChannelList, NULL);
241 if (freq != FREQUENCY_INVALID) {
242 return freq;
243 }
244 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_DBG, "no suitable 5G frequency");
245 }
246 return FREQUENCY_INVALID;
247 }
248
P2plinkGetGroupGrequency(const GcInfo * gc,const P2pLink5GList * channelList)249 int32_t P2plinkGetGroupGrequency(const GcInfo *gc, const P2pLink5GList *channelList)
250 {
251 if (gc == NULL) {
252 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "%s:invalid param.", __func__);
253 return SOFTBUS_INVALID_PARAM;
254 }
255
256 int32_t localStationFreq = P2pLinkUpateAndGetStationFreq(channelList);
257 int32_t gcStationFreq = gc->stationFrequency;
258
259 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_INFO, "local station freq = %d, gc station greq = %d.",
260 localStationFreq, gcStationFreq);
261 if (localStationFreq != -1 || gcStationFreq != -1) {
262 int32_t recommandFreq;
263 int32_t ret = P2pLinkGetRecommendChannel(&recommandFreq);
264 if (ret == SOFTBUS_OK) {
265 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_DBG, "get p2p recommand success, freq = %d.", recommandFreq);
266 return recommandFreq;
267 }
268 }
269
270 P2pLink5GList *gcChannelList = StringToChannelList(gc->channelList);
271 int32_t channel5gFreq = ChoseChannel5gFreq(gc, channelList, gcChannelList, localStationFreq, gcStationFreq);
272 SoftBusFree(gcChannelList);
273 if (channel5gFreq != -1) {
274 return channel5gFreq;
275 }
276
277 if (Is2GBand(localStationFreq)) {
278 return localStationFreq;
279 }
280
281 if (Is2GBand(gcStationFreq)) {
282 return gcStationFreq;
283 }
284
285 return FREQUENCY_2G_FIRST;
286 }