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 "nstackx_congestion.h"
17 #include "sys_congestion.h"
18 #include "nstackx_error.h"
19 #include "nstackx_log.h"
20 #include "nstackx_util.h"
21 #include "nstackx_dev.h"
22 #include "securec.h"
23
24 #define TAG "nStackXCongestion"
25 #define WIFI_THETA_ACCURACY 1000
26 #define PACKET_HEAD_BYTES 44
27 #define MS_NUM_PER_SECOND 1000
28 #define DATA_FRAME_SEND_INTERVAL_MS 5
29
30 #define WIFI_DIFS 34
31 #define WIFI_SIFS 16
32 #define WIFI_ACK 32
33 #define WIFI_RTS 28
34 #define WIFI_CTS 28
35 #define WIFI_SLOT 9
36 #define WIFI_WINDOW 8
37 #define WIFI_PLCP 5
38 #define WIFI_COMPENSATE_TIME 30
39 #define MB_SIZE 1048576
40
41 #define MAC_HEAD 14
42 #define IP_HEAD 20
43 #define UDP_HEAD 8
44
45 #define WIFI_ASSEMBLE_NUM 100
46 #define WIFI_ASSEMBLE_TIMES 8
47 #define ENHANCE_P2P_SPEED_NUMRATOR 120
48 #define ENHANCE_P2P_SPEED_DENOMINATOR 100
49 #define NSTACKX_LEAST_SENDRATE 3 // 3 packets per 5ms
50 #define NSTACKX_LEAST_SENDRATE_DMSG 1 // MBps
51
52 #define NSTACKX_MAX_CONNECTION_NUM 2
53
54 static WifiStationInfo g_txWifiStationInfo[NSTACKX_MAX_CONNECTION_NUM] = {{0}};
55
GetGTxWifiStationInfo(uint8_t socketIndex)56 WifiStationInfo GetGTxWifiStationInfo(uint8_t socketIndex)
57 {
58 return g_txWifiStationInfo[socketIndex];
59 }
60
CheckWlanNegoRateValid(uint32_t rate)61 int32_t CheckWlanNegoRateValid(uint32_t rate)
62 {
63 if (rate == 0 || rate > MAX_WIFI_NEGO_RATE) {
64 return NSTACKX_EFAILED;
65 }
66 return NSTACKX_EOK;
67 }
68
GetAssembleNumByBitrate(uint32_t speed)69 static inline uint32_t GetAssembleNumByBitrate(uint32_t speed)
70 {
71 uint32_t times = speed / WIFI_ASSEMBLE_NUM; /* Mbps */
72 return (times > 1) ? (times * WIFI_ASSEMBLE_TIMES) : WIFI_ASSEMBLE_TIMES;
73 }
74
GetEnhanceP2pSendRate(uint16_t speed)75 static inline uint16_t GetEnhanceP2pSendRate(uint16_t speed)
76 {
77 uint32_t ret = (uint32_t)(speed * ENHANCE_P2P_SPEED_NUMRATOR / ENHANCE_P2P_SPEED_DENOMINATOR);
78
79 ret = (ret > UINT16_MAX) ? UINT16_MAX : ret;
80 return (uint16_t)ret;
81 }
82
GetProtocolHead(void)83 static inline uint32_t GetProtocolHead(void)
84 {
85 return MAC_HEAD + IP_HEAD + UDP_HEAD;
86 }
87
GetWifiNonDataPacketConsumeTime(void)88 static inline uint32_t GetWifiNonDataPacketConsumeTime(void)
89 {
90 const uint32_t time = WIFI_DIFS + WIFI_SLOT * WIFI_WINDOW + WIFI_RTS + WIFI_SIFS + WIFI_CTS + WIFI_SIFS +
91 WIFI_SIFS + WIFI_ACK + WIFI_PLCP + WIFI_COMPENSATE_TIME;
92 return time;
93 }
94
GetThetaByLinkSpeed(uint32_t speedByte,uint32_t mtu)95 static inline uint32_t GetThetaByLinkSpeed(uint32_t speedByte, uint32_t mtu)
96 {
97 uint32_t assembleNum = GetAssembleNumByBitrate(speedByte * BITINBYTE);
98 uint32_t effectiveSize = mtu * assembleNum;
99 uint32_t allSize = (GetWifiNonDataPacketConsumeTime() * speedByte + (PACKET_HEAD_BYTES + mtu) * assembleNum);
100 // WIFI_THETA_ACCURACY, ratio accuracy per thousand
101 const uint32_t theta = (WIFI_THETA_ACCURACY * effectiveSize / allSize);
102 return theta;
103 }
104
GetSpeedRx(const WifiStationInfo * txWifiStationInfo,const WifiStationInfo * rxWifiStationInfo)105 static inline uint32_t GetSpeedRx(const WifiStationInfo *txWifiStationInfo, const WifiStationInfo *rxWifiStationInfo)
106 {
107 uint32_t speedRX;
108 if (rxWifiStationInfo->rxRate == 0) {
109 LOGE(TAG, "rxWifiStationInfo.txRateInfo.rateBitrate == 0");
110 speedRX = txWifiStationInfo->txRate / BITINBYTE;
111 } else {
112 speedRX = rxWifiStationInfo->rxRate / BITINBYTE;
113 }
114 return speedRX;
115 }
116
GetWlanConngestSendRate(const WifiStationInfo * txWifiStationInfo,const WifiStationInfo * rxWifiStationInfo,uint16_t * sendRateResult,uint32_t mtu)117 static int32_t GetWlanConngestSendRate(const WifiStationInfo *txWifiStationInfo,
118 const WifiStationInfo *rxWifiStationInfo, uint16_t *sendRateResult, uint32_t mtu)
119 {
120 if (CheckWlanNegoRateValid(rxWifiStationInfo->rxRate) != NSTACKX_EOK) {
121 LOGE(TAG, "recv endian tx rate error %u", rxWifiStationInfo->rxRate);
122 return NSTACKX_EFAILED;
123 }
124
125 uint32_t speedTX = txWifiStationInfo->txRate / BITINBYTE;
126 uint32_t speedRX = GetSpeedRx(txWifiStationInfo, rxWifiStationInfo);
127
128 uint32_t thetaTx = GetThetaByLinkSpeed(speedTX, mtu);
129 uint32_t thetaRx = GetThetaByLinkSpeed(speedRX, mtu);
130 uint32_t sendRateOri =
131 (speedTX * thetaTx / WIFI_THETA_ACCURACY * speedRX * thetaRx) / (speedTX * thetaTx + speedRX * thetaRx);
132
133 /* the packet num needed to be sent per 5 ms */
134 *sendRateResult = (uint16_t)(sendRateOri * MB_SIZE / (mtu + GetProtocolHead()) *
135 DATA_FRAME_SEND_INTERVAL_MS / MS_NUM_PER_SECOND);
136 if (*sendRateResult < NSTACKX_LEAST_SENDRATE) {
137 *sendRateResult = NSTACKX_LEAST_SENDRATE;
138 }
139
140 return NSTACKX_EOK;
141 }
142
GetP2pCongestSendRate(const WifiStationInfo * txWifiStationInfo,const WifiStationInfo * rxWifiStationInfo,uint16_t * sendRateResult,uint32_t mtu)143 static int32_t GetP2pCongestSendRate(const WifiStationInfo *txWifiStationInfo,
144 const WifiStationInfo *rxWifiStationInfo, uint16_t *sendRateResult, uint32_t mtu)
145 {
146 const WifiStationInfo *wifiStationInfo = txWifiStationInfo;
147 if (txWifiStationInfo->txRate < rxWifiStationInfo->txRate) {
148 wifiStationInfo = rxWifiStationInfo;
149 }
150
151 uint32_t speedTX = wifiStationInfo->txRate / BITINBYTE;
152 uint32_t thetaTx = GetThetaByLinkSpeed(speedTX, mtu);
153 uint32_t sendRateOri = speedTX * thetaTx / WIFI_THETA_ACCURACY;
154
155 /* the packet num needed to be sent per 5 ms */
156 uint16_t realSendRateResult =
157 (uint16_t)(sendRateOri * MB_SIZE / (uint32_t)mtu * DATA_FRAME_SEND_INTERVAL_MS / MS_NUM_PER_SECOND);
158 *sendRateResult = GetEnhanceP2pSendRate(realSendRateResult);
159 if (*sendRateResult < NSTACKX_LEAST_SENDRATE) {
160 *sendRateResult = NSTACKX_LEAST_SENDRATE;
161 }
162
163 return NSTACKX_EOK;
164 }
165
CheckMtu(uint32_t mtu)166 static inline int32_t CheckMtu(uint32_t mtu)
167 {
168 if (mtu <= MIN_MTU || mtu > MAX_MTU) {
169 return NSTACKX_EFAILED;
170 }
171 return NSTACKX_EOK;
172 }
173
174 /* calculate the sendrate for client */
GetConngestSendRate(WifiStationInfo * rxWifiStationInfo,uint16_t connType,uint32_t mtu,uint8_t socketIndex,uint16_t * sendRateResult)175 int32_t GetConngestSendRate(WifiStationInfo *rxWifiStationInfo, uint16_t connType, uint32_t mtu,
176 uint8_t socketIndex, uint16_t *sendRateResult)
177 {
178 int32_t ret;
179 if (CheckMtu(mtu) != NSTACKX_EOK) {
180 return NSTACKX_EFAILED;
181 }
182
183 if (connType == CONNECT_TYPE_WLAN) {
184 ret = GetWlanConngestSendRate(&g_txWifiStationInfo[socketIndex],
185 rxWifiStationInfo, sendRateResult, mtu);
186 } else if (connType == CONNECT_TYPE_P2P) {
187 ret = GetP2pCongestSendRate(&g_txWifiStationInfo[socketIndex],
188 rxWifiStationInfo, sendRateResult, mtu);
189 } else {
190 return NSTACKX_EFAILED;
191 }
192
193 return ret;
194 }
195
CheckDevNameValid(const char * devName)196 int32_t CheckDevNameValid(const char *devName)
197 {
198 if (devName == NULL || strlen(devName) == 0 || strlen(devName) > IF_NAMESIZE) {
199 return NSTACKX_EFAILED;
200 }
201 return NSTACKX_EOK;
202 }
203
204 /* get wifi info of server endian to send to client endian */
UpdateWifiStationInfo(const char * devName,WifiStationInfo * txWifiStationInfo,uint8_t socketIndex,int * changeStatus)205 int32_t UpdateWifiStationInfo(const char *devName, WifiStationInfo *txWifiStationInfo, uint8_t socketIndex,
206 int *changeStatus)
207 {
208 if (changeStatus != NULL) {
209 *changeStatus = 0;
210 }
211
212 if (CheckDevNameValid(devName) != NSTACKX_EOK || txWifiStationInfo == NULL) {
213 return NSTACKX_EFAILED;
214 }
215
216 (void)memset_s(txWifiStationInfo, sizeof(WifiStationInfo), 0, sizeof(WifiStationInfo));
217 int32_t ret = GetWifiInfo(devName, txWifiStationInfo);
218 if (ret != NSTACKX_EOK) {
219 return NSTACKX_EFAILED;
220 }
221 if (txWifiStationInfo->txRate != g_txWifiStationInfo[socketIndex].txRate) {
222 LOGI(TAG, "new.txRate %u old.txRate %u", txWifiStationInfo->txRate, g_txWifiStationInfo[socketIndex].txRate);
223 if (changeStatus != NULL) {
224 *changeStatus = 1;
225 }
226 }
227
228 return memcpy_s(&g_txWifiStationInfo[socketIndex], sizeof(g_txWifiStationInfo[socketIndex]),
229 txWifiStationInfo, sizeof(WifiStationInfo));
230 }
231
232 /* get wifi info of server endian to send to client endian */
GetServerWifiStationInfo(const char * devName,WifiStationInfo * wifiStationInfo)233 int32_t GetServerWifiStationInfo(const char *devName, WifiStationInfo *wifiStationInfo)
234 {
235 if (CheckDevNameValid(devName) != NSTACKX_EOK || wifiStationInfo == NULL) {
236 return NSTACKX_EFAILED;
237 }
238
239 return GetWifiInfo(devName, wifiStationInfo);
240 }
241
GetWifiInfoDMsg(const char * devName,WifiStationInfo * wifiStationInfo)242 int32_t GetWifiInfoDMsg(const char *devName, WifiStationInfo *wifiStationInfo)
243 {
244 if (CheckDevNameValid(devName) != NSTACKX_EOK) {
245 return NSTACKX_EFAILED;
246 }
247
248 return GetWifiInfo(devName, wifiStationInfo);
249 }
250
GetWlanConngestSendRateDMsg(uint32_t speedTX,uint32_t speedRX,uint32_t * sendRateResult,uint32_t mtu)251 static int32_t GetWlanConngestSendRateDMsg(uint32_t speedTX, uint32_t speedRX,
252 uint32_t *sendRateResult, uint32_t mtu)
253 {
254 if (CheckWlanNegoRateValid(speedTX) != NSTACKX_EOK || CheckWlanNegoRateValid(speedRX) != NSTACKX_EOK) {
255 LOGD(TAG, "wifi tx rate or rx rate invalid, tx=%u, rx=%u", speedTX, speedRX);
256 return NSTACKX_EFAILED;
257 }
258
259 speedTX = speedTX / BITINBYTE;
260 speedRX = speedRX / BITINBYTE;
261
262 uint32_t thetaTx = GetThetaByLinkSpeed(speedTX, mtu);
263 uint32_t thetaRx = GetThetaByLinkSpeed(speedRX, mtu);
264 // MBps
265 *sendRateResult =
266 (speedTX * thetaTx / WIFI_THETA_ACCURACY * speedRX * thetaRx) / (speedTX * thetaTx + speedRX * thetaRx);
267 if (*sendRateResult < NSTACKX_LEAST_SENDRATE_DMSG) {
268 *sendRateResult = NSTACKX_LEAST_SENDRATE_DMSG;
269 }
270
271 return NSTACKX_EOK;
272 }
273
GetP2pCongestSendRateDmsg(uint32_t speedTX,uint32_t speedRX,uint32_t * sendRateResult,uint32_t mtu)274 static int32_t GetP2pCongestSendRateDmsg(uint32_t speedTX, uint32_t speedRX,
275 uint32_t *sendRateResult, uint32_t mtu)
276 {
277 if (speedRX > speedTX) {
278 speedTX = speedRX;
279 }
280 speedTX = speedTX / BITINBYTE;
281 uint32_t thetaTx = GetThetaByLinkSpeed(speedTX, mtu);
282 *sendRateResult = speedTX * thetaTx / WIFI_THETA_ACCURACY;
283
284 if (*sendRateResult < NSTACKX_LEAST_SENDRATE_DMSG) {
285 *sendRateResult = NSTACKX_LEAST_SENDRATE_DMSG;
286 }
287
288 return NSTACKX_EOK;
289 }
290
GetConngestSendRateDMsg(const char * devName,uint32_t speedTX,uint32_t speedRX,uint32_t * sendRateResult,uint32_t mtu)291 int32_t GetConngestSendRateDMsg(const char *devName, uint32_t speedTX, uint32_t speedRX,
292 uint32_t *sendRateResult, uint32_t mtu)
293 {
294 if (CheckDevNameValid(devName) != NSTACKX_EOK) {
295 return NSTACKX_EFAILED;
296 }
297
298 if (strstr(devName, "p2p") != NULL) {
299 return GetP2pCongestSendRateDmsg(speedTX, speedRX, sendRateResult, mtu);
300 } else {
301 return GetWlanConngestSendRateDMsg(speedTX, speedRX, sendRateResult, mtu);
302 }
303 }
304