1 /*
2 * Copyright (C) 2022 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 "pcb.h"
17 #ifdef FILLP_SUPPORT_GSO
18 #include "check_gso_support.h"
19 #endif
20 #ifdef FILLP_LINUX
21 #include <netinet/udp.h>
22 #endif
23 #include "res.h"
24 #include "fillp_algorithm.h"
25 #include "spunge.h"
26 #include "fillp_mgt_msg_log.h"
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
SpungePcbRecv(void * argConn,void ** buf,FILLP_INT count)32 static FILLP_INT SpungePcbRecv(void *argConn, void **buf, FILLP_INT count)
33 {
34 struct FtNetconn *conn = (struct FtNetconn *)argConn;
35 struct FtSocket *sock = (struct FtSocket *)conn->sock;
36 FillpErrorType err = FillpQueuePush(conn->pcb->fpcb.recv.recvBox, buf, FILLP_TRUE, (FILLP_UINT)count);
37 if (err) {
38 FILLP_LOGERR("SpungePcbRecv: FillpQueuePush failed. sockId =%d", sock->index);
39
40 return err;
41 }
42
43 #ifdef SOCK_RECV_SEM
44 {
45 FILLP_INT tmp = count;
46
47 while (tmp--) {
48 (void)SYS_ARCH_SEM_POST(&SOCK_GET_RECVSEM(sock));
49 }
50 }
51 #endif /* SOCK_RECV_SEM */
52
53 SpungeEpollEventCallback(sock, SPUNGE_EPOLLIN, count);
54
55 return ERR_OK;
56 }
57
SpungePcbSend(void * arg,FILLP_CONST char * buf,FILLP_INT size,void * ppcb)58 static FILLP_INT SpungePcbSend(void *arg, FILLP_CONST char *buf,
59 FILLP_INT size, void *ppcb)
60 {
61 struct FtNetconn *conn = (struct FtNetconn *)arg;
62 struct SpungePcb *pcb = (struct SpungePcb *)ppcb;
63 struct SockOsSocket *osSock = NETCONN_GET_OSSOCK(conn, SPUNGE_GET_CUR_INSTANCE()->instIndex);
64
65 if (!OS_SOCK_OPS_FUNC_VALID(osSock, send)) {
66 return -1;
67 }
68
69 FILLP_PKT_SIMPLE_LOG(((struct FtSocket *)conn->sock)->index,
70 (FILLP_CONST struct FillpPktHead *)buf, FILLP_DIRECTION_TX);
71
72 if (size != (FILLP_INT) osSock->ioSock->ops->send(osSock->ioSock,
73 buf,
74 (FILLP_SIZE_T)((FILLP_UINT)size),
75 (struct sockaddr *)&pcb->remoteAddr,
76 pcb->addrLen)) {
77 return -1;
78 } else {
79 return size;
80 }
81 }
82
83 #ifdef FILLP_SUPPORT_GSO
84 #ifndef UDP_MAX_SEG
85 #define UDP_MAX_SEG 44
86 #endif
SendUdpSegmentCmsg(struct cmsghdr * cm)87 void SendUdpSegmentCmsg(struct cmsghdr *cm)
88 {
89 FILLP_UINT16 *valp = FILLP_NULL_PTR;
90 cm->cmsg_level = SOL_UDP;
91 cm->cmsg_type = UDP_SEGMENT;
92 cm->cmsg_len = CMSG_LEN(sizeof(FILLP_UINT16));
93 valp = (FILLP_UINT16 *)(void *)CMSG_DATA(cm);
94 *valp = CFG_MSS;
95 }
96
SpungePcbSendmsgInner(struct FtNetconn * conn,struct SpungePcb * spcb,SysIoUdpSock * udpSock,FILLP_INT size)97 static FILLP_INT SpungePcbSendmsgInner(struct FtNetconn *conn, struct SpungePcb *spcb,
98 SysIoUdpSock *udpSock, FILLP_INT size)
99 {
100 struct msghdr mh;
101 FILLP_CHAR control[CMSG_SPACE(sizeof(FILLP_UINT16))] = {0};
102 int ret;
103
104 if (conn->iovCount == 0) {
105 return 0;
106 }
107
108 mh.msg_name = (struct sockaddr *)&spcb->remoteAddr;
109 mh.msg_namelen = spcb->addrLen;
110 mh.msg_iov = conn->sendIov;
111 mh.msg_iovlen = conn->iovCount;
112 mh.msg_flags = 0;
113 if (conn->iovCount == 1) {
114 mh.msg_control = FILLP_NULL_PTR;
115 mh.msg_controllen = 0;
116 } else {
117 mh.msg_control = control;
118 mh.msg_controllen = sizeof(control);
119 SendUdpSegmentCmsg(CMSG_FIRSTHDR(&mh));
120 }
121 if (sendmsg(udpSock->udpSock, &mh, 0) < 0) {
122 ret = -1;
123 } else {
124 ret = size;
125 }
126 FILLP_LOGDTL("gso send %zu", conn->iovCount);
127
128 if (ret == -1 && errno == EIO) {
129 FILLP_INT sentFail = 0;
130 for (size_t i = 0; i < conn->iovCount; i++) {
131 /* EIO may be caused by netdevices not support checksum offload, so kernel gso return EIO.
132 * As kernel udp gso suggested, fallback to send.
133 */
134 ret = spcb->fpcb.sendFunc(conn, conn->sendIov[i].iov_base, conn->sendIov[i].iov_len, spcb);
135 if (ret <= 0) {
136 sentFail = 1;
137 break;
138 }
139 }
140
141 if (sentFail == 0) {
142 ret = size;
143 } else {
144 ret = -1;
145 }
146 FILLP_LOGERR("fallback to send, ret %d", ret);
147 spcb->fpcb.sendmsgEio = FILLP_TRUE;
148 }
149 conn->iovCount = 0;
150 return ret;
151 }
152
SpungePcbSendmsg(void * arg,FILLP_CONST char * buf,FILLP_INT size,void * pcb)153 FILLP_INT SpungePcbSendmsg(void *arg, FILLP_CONST char *buf, FILLP_INT size, void *pcb)
154 {
155 struct FtNetconn *conn = FILLP_NULL_PTR;
156 struct SockOsSocket *osSock = FILLP_NULL_PTR;
157 struct FillpPcb *fpcb = (struct FillpPcb *)pcb;
158 struct SpungePcb *spcb = (struct SpungePcb *)fpcb->spcb;
159 FILLP_UINT16 cfgMss = CFG_MSS;
160 FILLP_INT ret;
161 SysIoUdpSock *udpSock = FILLP_NULL_PTR;
162 FILLP_BOOL send = FILLP_FALSE;
163
164 if (buf == FILLP_NULL_PTR) {
165 conn = (struct FtNetconn *)spcb->conn;
166 } else {
167 conn = (struct FtNetconn *)arg;
168 }
169 osSock = NETCONN_GET_OSSOCK(conn, SPUNGE_GET_CUR_INSTANCE()->instIndex);
170 if (osSock == FILLP_NULL_PTR) {
171 return -1;
172 }
173
174 udpSock = (SysIoUdpSock *)osSock->ioSock;
175
176 if (buf == FILLP_NULL_PTR) {
177 ret = SpungePcbSendmsgInner(conn, spcb, udpSock, size);
178 return ret;
179 }
180
181 if (size < cfgMss) {
182 send = FILLP_TRUE;
183 }
184
185 conn->sendIov[conn->iovCount].iov_len = (size_t)(FILLP_UINT)size;
186 conn->sendIov[conn->iovCount].iov_base = (void *)buf;
187 conn->iovCount++;
188
189 if ((conn->iovCount < UDP_MAX_SEG) && (fpcb->isLast == FILLP_FALSE) && send == FILLP_FALSE) {
190 return size;
191 }
192 ret = SpungePcbSendmsgInner(conn, spcb, udpSock, size);
193 return ret;
194 }
195 #endif
SpcbAddPcbToSpinst(struct SpungeInstance * inst,struct SpungePcb * pcb)196 void SpcbAddPcbToSpinst(struct SpungeInstance *inst, struct SpungePcb *pcb)
197 {
198 SpinstAddToPcbList(inst, &pcb->udpNode);
199 }
200
SpcbDeleteFromSpinst(struct SpungeInstance * inst,struct SpungePcb * pcb)201 void SpcbDeleteFromSpinst(struct SpungeInstance *inst, struct SpungePcb *pcb)
202 {
203 SpinstDeleteFromPcbList(inst, &pcb->udpNode);
204 }
205
SpungePcbNew(void * argConn,struct SpungeInstance * inst)206 struct SpungePcb *SpungePcbNew(void *argConn, struct SpungeInstance *inst)
207 {
208 struct SpungePcb *pcb = (struct SpungePcb *)SpungeAlloc(1, sizeof(struct SpungePcb), SPUNGE_ALLOC_TYPE_CALLOC);
209 if (pcb == FILLP_NULL_PTR) {
210 FILLP_LOGERR("Failed allocate memory for spunge_pcb");
211 return FILLP_NULL_PTR;
212 }
213
214 pcb->conn = argConn;
215 pcb->fpcb.spcb = (void *)pcb;
216 pcb->fpcb.resInited = 0;
217
218 pcb->fpcb.mpRecvSize = 0;
219 pcb->fpcb.mpSendSize = 0;
220 pcb->fpcb.clientCookiePreserveTime = 0;
221 pcb->fpcb.pcbInst = inst;
222 pcb->fpcb.localUniqueId = 0;
223 pcb->fpcb.peerUniqueId = 0;
224 pcb->fpcb.send.pktStartNum = FILLP_CRYPTO_RAND();
225 pcb->fpcb.send.seqStartNum = FILLP_CRYPTO_RAND();
226
227 pcb->rateControl.recv.curMaxRateLimitation = 0;
228 pcb->rateControl.recv.weight = 0;
229
230 pcb->rateControl.send.curMaxRateLimitation = 0;
231 pcb->rateControl.send.weight = 0;
232
233 pcb->fpcb.pktSize = (FILLP_MAX_PKT_SIZE - FILLP_HLEN);
234 pcb->fpcb.recvFunc = SpungePcbRecv;
235 pcb->fpcb.sendFunc = SpungePcbSend;
236 #ifdef FILLP_SUPPORT_GSO
237 pcb->fpcb.sendmsgFunc = SpungePcbSendmsg;
238 (void)memset_s(pcb->devName, IFNAMESIZE, 0, IFNAMESIZE);
239 pcb->fpcb.sendmsgEio = FILLP_FALSE;
240 #endif
241 pcb->fpcb.isFinAckReceived = FILLP_FALSE;
242 SpcbAddPcbToSpinst(inst, pcb);
243 return pcb;
244 }
245
SpungePcbSetSendCacheSize(struct SpungePcb * pcb,FILLP_UINT32 cacheSize)246 void SpungePcbSetSendCacheSize(struct SpungePcb *pcb, FILLP_UINT32 cacheSize)
247 {
248 pcb->fpcb.mpSendSize = cacheSize;
249 }
250
SpungePcbSetRecvCacheSize(struct SpungePcb * pcb,FILLP_UINT32 cacheSize)251 void SpungePcbSetRecvCacheSize(struct SpungePcb *pcb, FILLP_UINT32 cacheSize)
252 {
253 pcb->fpcb.mpRecvSize = cacheSize;
254 }
255
SpungePcbSetPktSize(struct SpungePcb * pcb,FILLP_UINT32 pktSize)256 void SpungePcbSetPktSize(struct SpungePcb *pcb, FILLP_UINT32 pktSize)
257 {
258 pcb->fpcb.pktSize = pktSize;
259 }
260
SpungePcbSetOppositeRate(struct SpungePcb * pcb,FILLP_UINT32 rate)261 void SpungePcbSetOppositeRate(struct SpungePcb *pcb, FILLP_UINT32 rate)
262 {
263 pcb->fpcb.recv.oppositeSetRate = rate;
264 }
265
SpungePcbSetSlowStart(struct SpungePcb * pcb,FILLP_BOOL slowStart)266 void SpungePcbSetSlowStart(struct SpungePcb *pcb, FILLP_BOOL slowStart)
267 {
268 pcb->fpcb.send.slowStart = slowStart;
269 }
270
SpungePcbSetPackInterval(struct SpungePcb * pcb,FILLP_UINT32 interval)271 void SpungePcbSetPackInterval(struct SpungePcb *pcb, FILLP_UINT32 interval)
272 {
273 pcb->fpcb.statistics.pack.packInterval = interval;
274 pcb->fpcb.packTimerNode.interval = interval;
275 pcb->fpcb.FcTimerNode.interval = interval;
276 }
277
SpungePcbSetAddrType(struct SpungePcb * pcb,FILLP_UINT16 addrType)278 void SpungePcbSetAddrType(struct SpungePcb *pcb, FILLP_UINT16 addrType)
279 {
280 pcb->addrType = addrType;
281 }
282
SpungePcbSetLocalPort(struct SpungePcb * pcb,FILLP_INT port)283 void SpungePcbSetLocalPort(struct SpungePcb *pcb, FILLP_INT port)
284 {
285 pcb->localPort = port;
286 }
287
SpungePcbSetDirectlySend(struct SpungePcb * pcb,FILLP_INT directlySend)288 void SpungePcbSetDirectlySend(struct SpungePcb *pcb, FILLP_INT directlySend)
289 {
290 pcb->fpcb.send.directlySend = directlySend;
291 }
292
SpungePcbRemove(struct SpungePcb * pcb)293 void SpungePcbRemove(struct SpungePcb *pcb)
294 {
295 struct FtNetconn *conn = FILLP_NULL_PTR;
296 struct SockOsSocket *osSock = FILLP_NULL_PTR;
297 if (pcb == FILLP_NULL_PTR) {
298 FILLP_LOGERR("SpungePcbRemove: Invalid parameters passed");
299 return;
300 }
301
302 conn = (struct FtNetconn *)pcb->conn;
303 SpcbDeleteFromSpinst(pcb->fpcb.pcbInst, pcb);
304 FillpRemovePcb(&pcb->fpcb);
305 if (conn != FILLP_NULL_PTR) {
306 osSock = NETCONN_GET_OSSOCK(conn, SPUNGE_GET_CUR_INSTANCE()->instIndex);
307 if (OS_SOCK_OPS_FUNC_VALID(osSock, removePcb)) {
308 // If alloc sock fails, the free code will go to here, sock->netconn->osSocket will be null
309 osSock->ioSock->ops->removePcb(osSock->ioSock, conn->pcb);
310 }
311 }
312
313 SpungeFree(pcb, SPUNGE_ALLOC_TYPE_CALLOC);
314 }
315
316 #ifdef __cplusplus
317 }
318 #endif
319