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 "socket_opt.h"
17 #include "sockets.h"
18 #include "socket_common.h"
19 #include "spunge.h"
20 #include "spunge_message.h"
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
SockGetOptSendCache(struct FtSocket * sock,void * optVal,FILLP_INT * optLen)26 static FILLP_INT SockGetOptSendCache(struct FtSocket *sock, void *optVal, FILLP_INT *optLen)
27 {
28     struct FillpCurrentSendCacheInf *currentSendCacheInfo = FILLP_NULL_PTR;
29     struct FillpSendPcb *sendPcb = FILLP_NULL_PTR;
30     if ((*optLen < (FILLP_INT)sizeof(struct FillpCurrentSendCacheInf)) || (sock->netconn == FILLP_NULL_PTR)) {
31         SET_ERRNO(FILLP_EINVAL);
32         return -1;
33     }
34     if ((sock->netconn == FILLP_NULL_PTR) || (sock->netconn->state != CONN_STATE_CONNECTED)) {
35         FILLP_LOGERR("SockGetSockOpt: sock state must be connected Invalid sock = %d", sock->index);
36         SET_ERRNO(FILLP_EBADF);
37         return -1;
38     }
39 
40     currentSendCacheInfo = (struct FillpCurrentSendCacheInf *)optVal;
41     sendPcb = &(sock->netconn->pcb->fpcb.send);
42     currentSendCacheInfo->currentSendCacheSize = sendPcb->curItemCount;
43     currentSendCacheInfo->currentDataSizeInCache = (FILLP_UINT32)(sendPcb->unSendList.size +
44         sendPcb->unackList.count + sendPcb->redunList.nodeNum + sendPcb->unrecvList.nodeNum +
45         sendPcb->itemWaitTokenLists.nodeNum);
46 
47     return ERR_OK;
48 }
49 
SockGetSockOptFillp(struct FtSocket * sock,FILLP_INT optName,void * optVal,FILLP_INT * optLen)50 static FILLP_INT SockGetSockOptFillp(struct FtSocket *sock, FILLP_INT optName, void *optVal, FILLP_INT *optLen)
51 {
52     FILLP_INT err;
53     switch (optName) {
54         case FILLP_PKT_DATA_OPTS_TIMESTAMP:
55             if (*optLen < (FILLP_INT)sizeof(FILLP_INT)) {
56                 SET_ERRNO(FILLP_EINVAL);
57                 err = -1;
58                 break;
59             }
60             if (sock->dataOptionFlag & FILLP_OPT_FLAG_TIMESTAMP) {
61                 *(FILLP_INT *)optVal = 1;
62                 *optLen = (FILLP_INT)sizeof(FILLP_INT);
63             } else {
64                 *(FILLP_INT *)optVal = 0;
65                 *optLen = (FILLP_INT)sizeof(FILLP_INT);
66             }
67             err = ERR_OK;
68             break;
69         case FILLP_SOCK_SEND_CACHE_INFO:
70             err = SockGetOptSendCache(sock, optVal, optLen);
71             break;
72         case SO_LINGER:
73             if (*optLen < (FILLP_INT)sizeof(struct linger)) {
74                 SET_ERRNO(FILLP_EINVAL);
75                 err = -1;
76             } else {
77                 err = memcpy_s(optVal, (FILLP_UINT32)(*optLen), (void *)&sock->fillpLinger, sizeof(struct linger));
78                 if (err != EOK) {
79                     FILLP_LOGERR("memcpy_s failed with errcode %d", err);
80                     SET_ERRNO(FILLP_EINVAL);
81                     err = -1;
82                 } else {
83                     *optLen = (FILLP_INT)sizeof(struct linger);
84                     err = ERR_OK;
85                 }
86             }
87             break;
88         default:
89             SET_ERRNO(FILLP_EINVAL);
90             err = -1;
91             break;
92     }
93     return err;
94 }
95 
SockGetSockOpt(FILLP_INT sockIndex,FILLP_INT level,FILLP_INT optName,void * optVal,FILLP_INT * optLen)96 FILLP_INT SockGetSockOpt(
97     FILLP_INT           sockIndex,
98     FILLP_INT           level,
99     FILLP_INT           optName,
100     void               *optVal,
101     FILLP_INT          *optLen)
102 {
103     struct FtSocket *sock = SockApiGetAndCheck(sockIndex);
104     struct SockOsSocket *osSock = FILLP_NULL_PTR;
105     FillpErrorType err = ERR_OK;
106 
107     FILLP_LOGINF("SockGetSockOpt: sock = %d", sockIndex);
108 
109     if (sock == FILLP_NULL_PTR) {
110         return -1;
111     }
112 
113     if ((optLen == FILLP_NULL_PTR) || (optVal == FILLP_NULL_PTR)) {
114         (void)SYS_ARCH_RWSEM_RDPOST(&sock->sockConnSem);
115         SET_ERRNO(FILLP_EFAULT);
116         FILLP_LOGERR("SockGetSockOpt: optLen or optVal NULL");
117         return -1;
118     }
119 
120     if ((optName == SO_ERROR) && (level == SOL_SOCKET)) {
121         if (*optLen < (FILLP_INT)sizeof(int)) {
122             (void)SYS_ARCH_RWSEM_RDPOST(&sock->sockConnSem);
123             SET_ERRNO(FILLP_EINVAL);
124             return -1;
125         }
126 
127         if (sock->err == FILLP_EINPROGRESS) {
128             int errToErrno = FillpErrToErrno(sock->netconn->lastErr);
129             FILLP_SOCK_SET_ERR(sock, errToErrno);
130         }
131 
132         *(int *)optVal = sock->err;
133         sock->err = ERR_OK;
134     } else if (level == IPPROTO_FILLP) {
135         err = SockGetSockOptFillp(sock, optName, optVal, optLen);
136     } else {
137         osSock = NETCONN_GET_OSSOCK(sock->netconn, sock->inst->instIndex);
138         if (!OS_SOCK_OPS_FUNC_VALID(osSock, getsockopt)) {
139             SET_ERRNO(FILLP_EINVAL);
140             err = -1;
141         } else {
142             err = osSock->ioSock->ops->getsockopt(osSock->ioSock, level, optName, optVal, optLen);
143         }
144     }
145 
146     (void)SYS_ARCH_RWSEM_RDPOST(&sock->sockConnSem);
147     FILLP_LOGINF("SockGetSockOpt: return fillp_sock_id:%d, err:%d", sockIndex, err);
148 
149     if (err != ERR_OK) {
150         err = -1;
151     }
152 
153     return err;
154 }
155 
SockSetOptTimestamp(struct FtSocket * sock,FILLP_CONST void * optVal,socklen_t optLen)156 static FILLP_INT SockSetOptTimestamp(struct FtSocket *sock, FILLP_CONST void *optVal, socklen_t optLen)
157 {
158     FILLP_INT err;
159 
160     if (optLen < (FILLP_INT)sizeof(FILLP_INT)) {
161         SET_ERRNO(FILLP_EINVAL);
162         return ERR_PARAM;
163     }
164 
165     if (*(FILLP_CONST FILLP_INT *)optVal) {
166         err = SockUpdatePktDataOpt(sock, (FILLP_UINT16)FILLP_OPT_FLAG_TIMESTAMP, 0);
167     } else {
168         err = SockUpdatePktDataOpt(sock, 0, (FILLP_UINT16)FILLP_OPT_FLAG_TIMESTAMP);
169     }
170     if (err != ERR_OK) {
171         SET_ERRNO(FILLP_EINVAL);
172     }
173 
174     return err;
175 }
176 
SockSetOptLinger(struct FtSocket * sock,FILLP_CONST void * optVal,socklen_t optLen)177 static FILLP_INT SockSetOptLinger(struct FtSocket *sock, FILLP_CONST void *optVal, socklen_t optLen)
178 {
179     FILLP_INT err = ERR_PARAM;
180     if (optLen < (FILLP_INT)sizeof(struct linger)) {
181         SET_ERRNO(FILLP_EINVAL);
182     } else {
183         err = memcpy_s((void *)&sock->fillpLinger, sizeof(struct linger), optVal, (FILLP_UINT32)optLen);
184         if (err != EOK) {
185             FILLP_LOGERR("memcpy_s failed with errcode %d", err);
186             SET_ERRNO(FILLP_EINVAL);
187             err = ERR_PARAM;
188         }
189     }
190 
191     return err;
192 }
193 
SockSetFcAlg(struct FtSocket * sock,FILLP_UINT32 alg)194 static FILLP_INT SockSetFcAlg(struct FtSocket *sock, FILLP_UINT32 alg)
195 {
196     FILLP_UINT8 connState;
197 
198     if (sock->netconn == FILLP_NULL_PTR) {
199         FILLP_LOGERR("netconn is NULL, fillp_sock_id:%d", sock->index);
200         return FILLP_EINVAL;
201     }
202 
203     connState = NETCONN_GET_STATE(sock->netconn);
204     if (connState != CONN_STATE_IDLE) {
205         FILLP_LOGERR("Netconn state is not idle fillp_sock_id:%d,state:%u", sock->index, connState);
206         return FILLP_EINVAL;
207     }
208 
209     if (sock->netconn->pcb == FILLP_NULL_PTR) {
210         FILLP_LOGERR("pcb is NULL, fillp_sock_id:%d", sock->index);
211         return FILLP_EINVAL;
212     }
213 
214     if (alg != FILLP_ALG_ONE && alg != FILLP_ALG_TWO && alg != FILLP_ALG_THREE &&
215         alg != FILLP_ALG_MSG && alg != FILLP_ALG_BASE) {
216         FILLP_LOGERR("alg %u is not supported", alg);
217         return FILLP_EINVAL;
218     }
219 
220     if (alg != FILLP_ALG_BASE) {
221         sock->netconn->pcb->fpcb.fcAlg = (FILLP_UINT8)FILLP_SUPPORT_ALG_N(alg);
222     } else {
223         sock->netconn->pcb->fpcb.fcAlg = FILLP_SUPPORT_ALG_BASE;
224     }
225     if (alg == FILLP_ALG_MSG) {
226         sock->resConf.common.recvCache = FILLP_DEFAULT_MSG_RECV_CACHE;
227         sock->resConf.common.sendCache = FILLP_DEFAULT_MSG_SEND_CACHE;
228         NetconnSetRecvCacheSize(sock->netconn, sock->resConf.common.recvCache);
229         NetconnSetSendCacheSize(sock->netconn, sock->resConf.common.sendCache);
230     }
231     return FILLP_OK;
232 }
233 
SockSetOptFcAlg(struct FtSocket * sock,FILLP_CONST void * optVal,socklen_t optLen)234 static FILLP_INT SockSetOptFcAlg(struct FtSocket *sock, FILLP_CONST void *optVal, socklen_t optLen)
235 {
236     FILLP_INT err = ERR_PARAM;
237 
238     if (optLen < (FILLP_INT)sizeof(FILLP_UINT32)) {
239         SET_ERRNO(FILLP_EINVAL);
240         return err;
241     }
242 
243     if (SockSetFcAlg(sock, *(FILLP_UINT32 *)optVal) != ERR_OK) {
244         SET_ERRNO(FILLP_EINVAL);
245     } else {
246         err = 0;
247     }
248 
249     return err;
250 }
251 
SockSetOptDirectlySend(struct FtSocket * sock,FILLP_CONST void * optVal,socklen_t optLen)252 static FILLP_INT SockSetOptDirectlySend(struct FtSocket *sock, FILLP_CONST void *optVal, socklen_t optLen)
253 {
254     if (optLen < (FILLP_INT)sizeof(FILLP_INT)) {
255         SET_ERRNO(FILLP_EINVAL);
256         return ERR_PARAM;
257     }
258 
259     sock->directlySend = *(FILLP_INT *)optVal;
260     FILLP_LOGBUTT("fillp sock id: %d, set directlySend to %d", sock->index, sock->directlySend);
261     return ERR_OK;
262 }
263 
SockSetSockOptFillp(struct FtSocket * sock,FILLP_INT optName,FILLP_CONST void * optVal,socklen_t optLen)264 static FILLP_INT SockSetSockOptFillp(struct FtSocket *sock,
265     FILLP_INT optName, FILLP_CONST void *optVal, socklen_t optLen)
266 {
267     FILLP_INT err = -1;
268     switch (optName) {
269         case FILLP_PKT_DATA_OPTS_TIMESTAMP:
270             err = SockSetOptTimestamp(sock, optVal, optLen);
271             break;
272         case SO_LINGER:
273             err = SockSetOptLinger(sock, optVal, optLen);
274             break;
275         case FILLP_SOCK_FC_ALG:
276             err = SockSetOptFcAlg(sock, optVal, optLen);
277             break;
278         case FILLP_SOCK_DIRECTLY_SEND:
279             err = SockSetOptDirectlySend(sock, optVal, optLen);
280             break;
281         default:
282             SET_ERRNO(FILLP_EINVAL);
283             break;
284     }
285     return err;
286 }
287 
SockSetSockOpt(FILLP_INT sockIndex,FILLP_INT level,FILLP_INT optName,FILLP_CONST void * optVal,socklen_t optLen)288 FILLP_INT SockSetSockOpt(
289     FILLP_INT           sockIndex,
290     FILLP_INT           level,
291     FILLP_INT           optName,
292     FILLP_CONST void   *optVal,
293     socklen_t           optLen)
294 {
295     struct FtSocket *sock = FILLP_NULL_PTR;
296     struct SockOsSocket *osSock = FILLP_NULL_PTR;
297     FillpErrorType err = -1;
298 
299     FILLP_LOGINF("SockSetSockOpt: sock = %d", sockIndex);
300 
301     if (optVal == FILLP_NULL_PTR) {
302         SET_ERRNO(FILLP_EFAULT);
303         return err;
304     }
305 
306     if ((level == SOL_SOCKET) && ((optName == SO_SNDBUF) || (optName == SO_RCVBUF))) {
307         FILLP_LOGERR("SockSetSockOpt: sock = %d invalid param optName=%d", sockIndex, optName);
308         SET_ERRNO(FILLP_EOPNOTSUPP);
309         return err;
310     }
311 
312     sock = SockApiGetAndCheck(sockIndex);
313     if (sock == FILLP_NULL_PTR) {
314         return err;
315     }
316 
317     if (level == IPPROTO_FILLP) {
318         err = SockSetSockOptFillp(sock, optName, optVal, optLen);
319     } else {
320         osSock = NETCONN_GET_OSSOCK(sock->netconn, sock->inst->instIndex);
321         if (OS_SOCK_OPS_FUNC_VALID(osSock, setsockopt)) {
322             err = osSock->ioSock->ops->setsockopt(osSock->ioSock, level, optName, optVal, optLen);
323         } else {
324             SET_ERRNO(FILLP_EINVAL);
325         }
326     }
327 
328     if (err != ERR_OK) {
329         err = -1;
330     }
331 
332     (void)SYS_ARCH_RWSEM_RDPOST(&sock->sockConnSem);
333     FILLP_LOGINF("SockSetSockOpt: return fillp_sock_id:%d, err:%d", sockIndex, err);
334 
335     return err;
336 }
337 
338 #ifdef __cplusplus
339 }
340 #endif
341