1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
5 # Licensed under the Apache License, Version 2.0 (the "License"); #
6 # you may not use this file except in compliance with the License. #
7 # You may obtain a copy of the License at #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
11 # Unless required by applicable law or agreed to in writing, software #
12 # distributed under the License is distributed on an "AS IS" BASIS, #
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
14 # See the License for the specific language governing permissions and #
15 # limitations under the License. #
16 ################################################################################
17 *******************************************************************************/
19 /* This file contains all SCTP related functionality */
21 #include "common_def.h"
22 #include "OCTET_STRING.h"
23 #include "cu_f1ap_msg_hdl.h"
24 #include "cu_stub_sctp.h"
25 #include "cu_stub_egtp.h"
34 /**************************************************************************
35 * @brief Task Initiation callback function.
39 * Function : sctpActvInit
42 * This function is supplied as one of parameters during SCTP's
43 * task registration. SSI will invoke this function once, after
44 * it creates and attaches this TAPA Task to a system task.
46 * @param[in] Ent entity, the entity ID of this task.
47 * @param[in] Inst inst, the instance ID of this task.
48 * @param[in] Region region, the region ID registered for memory
50 * @param[in] Reason reason.
51 * @return ROK - success
53 ***************************************************************************/
54 uint8_t sctpActvInit()
56 DU_LOG("\n\nDEBUG --> SCTP : Initializing");
57 memset(&sctpCb, 0, sizeof(SctpGlobalCb));
58 sctpCb.sctpCfg = cuCb.cuCfgParams.sctpParams;
62 /**************************************************************************
63 * @brief Task Activation callback function.
67 * Function : sctpActvTsk
70 * This function handles all SCTP messages received
71 * This API is registered with SSI during the
72 * Task Registration of DU APP.
74 * @param[in] Pst *pst, Post structure of the primitive.
75 * @param[in] Buffer *mBuf, Packed primitive parameters in the
77 * @return ROK - success
80 ***************************************************************************/
81 uint8_t sctpActvTsk(Pst *pst, Buffer *mBuf)
88 /**************************************************************************
89 * @brief Function to configure the Sctp Params during config Request
93 * Function : duSctpCfgReq
96 * This function configures SCTP Params during the config Request
98 * @return ROK - success
101 ***************************************************************************/
105 int destIdx = 0, assocIdx = 0;
107 fillAddrLst(&sctpCb.localAddrLst, &sctpCb.sctpCfg.localIpAddr);
108 memset(&sctpCb.f1LstnSockFd, -1, sizeof(CmInetFd));
110 for(destIdx=0; destIdx < sctpCb.sctpCfg.f1SctpInfo.numDestNode; destIdx++)
112 sctpCb.assocCb[assocIdx].intf = F1_INTERFACE;
113 sctpCb.assocCb[assocIdx].destPort = sctpCb.sctpCfg.f1SctpInfo.destCb[destIdx].destPort;
114 sctpCb.assocCb[assocIdx].bReadFdSet = ROK;
115 memset(&sctpCb.assocCb[assocIdx].sockFd, -1, sizeof(CmInetFd));
116 fillDestNetAddr(&sctpCb.assocCb[assocIdx].destIpNetAddr, &sctpCb.sctpCfg.f1SctpInfo.destCb[destIdx].destIpAddr);
120 sctpCb.localXnNodeType = sctpCb.sctpCfg.xnSctpInfo.localNodeType;
121 for(destIdx=0; destIdx < sctpCb.sctpCfg.xnSctpInfo.numDestNode; destIdx++)
123 sctpCb.assocCb[assocIdx].intf = XN_INTERFACE;
124 sctpCb.assocCb[assocIdx].destPort = sctpCb.sctpCfg.xnSctpInfo.destCb[destIdx].destPort;
125 sctpCb.assocCb[assocIdx].bReadFdSet = ROK;
126 memset(&sctpCb.assocCb[assocIdx].sockFd, -1, sizeof(CmInetFd));
127 fillDestNetAddr(&sctpCb.assocCb[assocIdx].destIpNetAddr, &sctpCb.sctpCfg.xnSctpInfo.destCb[destIdx].destIpAddr);
130 sctpCb.numAssoc = assocIdx;
135 /*******************************************************************
137 * @brief Fills the address List of the source Ip Address
141 * Function : fillAddrLst
144 * Fills the address List of source Ip Address
146 * @params[in] CmInetNetAddrLst *addrLstPtr, Address List pointer
147 * @params[in] F1IpAddr *srcIpAddr, src Ip Adrress to be filled in the Address List
148 * @return ROK - success
151 ******************************************************************/
153 uint8_t fillAddrLst(CmInetNetAddrLst *addrLstPtr, SctpIpAddr *ipAddr)
155 addrLstPtr->addrs[addrLstPtr->count].type = CM_INET_IPV4ADDR_TYPE;
156 addrLstPtr->addrs[addrLstPtr->count].u.ipv4NetAddr = CM_INET_NTOH_UINT32(ipAddr->ipV4Addr);
161 /******************************************************************************
163 * @brief Fills the address List of the source Ip Address
167 * Function : fillDestNetAddr
170 * Fills the address List of destinatoion Ip Address
172 * @params[in] CmInetNetAddr *destAddrPtr, Address List pointer
173 * @params[in] F1IpAddr *dstIpAddr, destIp Address to be filled in the Address List
174 * @return ROK - success
177 *******************************************************************************/
178 uint8_t fillDestNetAddr(CmInetNetAddr *destAddrPtr, SctpIpAddr *dstIpPtr)
180 /* Filling destination address */
181 destAddrPtr->type = CM_INET_IPV4ADDR_TYPE;
182 destAddrPtr->u.ipv4NetAddr = CM_INET_NTOH_UINT32(dstIpPtr->ipV4Addr);
186 /******************************************************************************
188 * @brief Eastablishes the Assoc Req for the received interface type
192 * Function : sctpStartReq
195 * Eastablishes the Assoc Req for the received interface type
197 * @params[in] DuSctpDestCb *paramPtr
198 * @return ROK - success
201 *******************************************************************************/
203 uint8_t sctpStartReq()
209 socket_type = CM_INET_STREAM;
211 /* Establish SCTP association at XN interface */
212 if(sctpCb.sctpCfg.xnSctpInfo.numDestNode)
214 if(sctpCb.localXnNodeType == SERVER)
216 if((ret = cmInetSocket(socket_type, &sctpCb.xnLstnSockFd, IPPROTO_SCTP) != ROK))
218 DU_LOG("\nERROR --> SCTP : Socket[%d] coudnt open for listening", sctpCb.f1LstnSockFd.fd);
220 else if((ret = cmInetSctpBindx(&sctpCb.xnLstnSockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.xnSctpInfo.port)) != ROK)
222 DU_LOG("\nERROR --> SCTP: Binding failed at CU");
224 else if(ret = cmInetListen(&sctpCb.xnLstnSockFd, 1) != ROK)
226 DU_LOG("\nERROR --> SCTP : Listening on socket failed");
227 cmInetClose(&sctpCb.xnLstnSockFd);
232 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
234 if(sctpCb.assocCb[assocIdx].intf == XN_INTERFACE)
236 if((ret = sctpAccept(&sctpCb.xnLstnSockFd, &sctpCb.assocCb[assocIdx])) != ROK)
238 DU_LOG("\nERROR --> SCTP: Unable to accept the connection at CU");
244 else if(sctpCb.localXnNodeType == CLIENT)
246 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
248 if(sctpCb.assocCb[assocIdx].intf == XN_INTERFACE)
250 if((ret = cmInetSocket(socket_type, &sctpCb.assocCb[assocIdx].sockFd, IPPROTO_SCTP)) != ROK)
252 DU_LOG("\nERROR --> SCTP : Failed while opening a socket in ODU");
254 else if((ret = cmInetSctpBindx(&sctpCb.assocCb[assocIdx].sockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.xnSctpInfo.port)) != ROK)
256 DU_LOG("\nERROR --> SCTP: Failed during Binding in ODU");
258 else if((ret = sctpSetSockOpts(&sctpCb.assocCb[assocIdx].sockFd)) != ROK)
260 DU_LOG("\nERROR --> SCTP : Failed to set Socket Opt in ODU");
266 DU_LOG("\nERROR --> SCTP : Failed while establishing Req at DU");
271 ret = cmInetSctpConnectx(&sctpCb.assocCb[assocIdx].sockFd, &sctpCb.assocCb[assocIdx].destIpNetAddr, \
272 &sctpCb.assocCb[assocIdx].destAddrLst, sctpCb.assocCb[assocIdx].destPort);
273 /* 115 error_code indicates that Operation is in progress and hence ignored if SctpConnect failed due to this */
285 /* Establish SCTP association at F1 interface */
286 if(sctpCb.sctpCfg.f1SctpInfo.numDestNode)
288 if((ret = cmInetSocket(socket_type, &sctpCb.f1LstnSockFd, IPPROTO_SCTP) != ROK))
290 DU_LOG("\nERROR --> SCTP : Socket[%d] coudnt open for listening", sctpCb.f1LstnSockFd.fd);
292 else if((ret = cmInetSctpBindx(&sctpCb.f1LstnSockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.f1SctpInfo.port)) != ROK)
294 DU_LOG("\nERROR --> SCTP: Binding failed at CU");
296 else if(ret = cmInetListen(&sctpCb.f1LstnSockFd, 1) != ROK)
298 DU_LOG("\nERROR --> SCTP : Listening on socket failed");
299 cmInetClose(&sctpCb.f1LstnSockFd);
304 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
306 if(sctpCb.assocCb[assocIdx].intf == F1_INTERFACE)
308 if((ret = sctpAccept(&sctpCb.f1LstnSockFd, &sctpCb.assocCb[assocIdx])) != ROK)
310 DU_LOG("\nERROR --> SCTP: Unable to accept the connection at CU");
319 if(sctpSockPoll() != ROK)
321 DU_LOG("\nERROR --> SCTP: Polling failed to start at CU");
327 /*******************************************************************
329 * @brief Sets socket options as per requirement
333 * Function : sctpSetSockOpts
336 * Sets socket options as per requirement
339 * @return ROK - success
342 * ****************************************************************/
343 uint8_t sctpSetSockOpts(CmInetFd *sock_Fd)
346 CmSctpEvent sctpEvent;
348 sctpEvent.dataIoEvent = TRUE;
349 sctpEvent.associationEvent = TRUE;
350 sctpEvent.addressEvent = TRUE;
351 sctpEvent.sendFailureEvent = TRUE;
352 sctpEvent.peerErrorEvent = TRUE;
353 sctpEvent.shutdownEvent = TRUE;
354 sctpEvent.partialDeliveryEvent = TRUE;
355 sctpEvent.adaptationLayerEvent = TRUE;
357 if((ret = cmInetSetOpt(sock_Fd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent)) != ROK)
365 /*******************************************************************
367 * @brief Initiates connection with peer SCTP
371 * Function : sctpAccept
374 * Establishes SCTP connection with peer.
375 * Here, DU-SCTP will initate connection towards CU-SCTP
378 * @return ROK - success
381 * ****************************************************************/
382 uint8_t sctpAccept(CmInetFd *lstnSockFd, CuSctpAssocCb *assocCb)
386 DU_LOG("\nINFO --> SCTP : Connecting");
388 while(!assocCb->connUp)
390 ret = cmInetAccept(lstnSockFd, &assocCb->peerAddr, &assocCb->sockFd);
397 DU_LOG("\nERROR --> SCTP : Failed to accept connection");
402 assocCb->connUp = TRUE;
403 sctpSetSockOpts(&assocCb->sockFd);
407 DU_LOG("\nINFO --> SCTP : Connection established");
412 /*******************************************************************
414 * @brief Handles an SCTP notification message
418 * Function : sctpNtfyHdlr
421 * Handles an SCTP notification message
423 * @params[in] Notify message
425 * @return ROK - success
428 * ****************************************************************/
429 uint8_t sctpNtfyHdlr(CuSctpAssocCb *assocCb, CmInetSctpNotification *ntfy)
431 switch(ntfy->header.nType)
433 case CM_INET_SCTP_ASSOC_CHANGE :
434 DU_LOG("\nINFO --> SCTP : Assoc change notification received");
435 switch(ntfy->u.assocChange.state)
437 case CM_INET_SCTP_COMM_UP:
438 DU_LOG("DEBUG --> Event : COMMUNICATION UP");
439 assocCb->connUp = TRUE;
441 case CM_INET_SCTP_COMM_LOST:
442 DU_LOG("DEBUG --> Event : COMMUNICATION LOST");
443 assocCb->connUp = FALSE;
445 case CM_INET_SCTP_RESTART:
446 DU_LOG("DEBUG --> Event : SCTP RESTART");
447 assocCb->connUp = FALSE;
449 case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */
450 DU_LOG("DEBUG --> Event : SHUTDOWN COMPLETE");
451 assocCb->connUp = FALSE;
453 case CM_INET_SCTP_CANT_STR_ASSOC:
454 DU_LOG("DEBUG --> Event : CANT START ASSOC");
455 assocCb->connUp = FALSE;
458 DU_LOG("\nERROR --> Invalid event");
462 case CM_INET_SCTP_PEER_ADDR_CHANGE :
463 DU_LOG("\nINFO --> SCTP : Peer Address Change notificarion received");
464 /* Need to add handler */
466 case CM_INET_SCTP_REMOTE_ERROR :
467 DU_LOG("\nINFO --> SCTP : Remote Error notification received");
469 case CM_INET_SCTP_SEND_FAILED :
470 DU_LOG("\nINFO --> SCTP : Send Failed notification received\n");
472 case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */
473 DU_LOG("\nINFO --> SCTP : Shutdown Event notification received\n");
474 assocCb->connUp = FALSE;
477 case CM_INET_SCTP_ADAPTATION_INDICATION :
478 DU_LOG("\nINFO --> SCTP : Adaptation Indication received\n");
480 case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
481 DU_LOG("\nINFO --> SCTP : Partial Delivery Event received\n");
484 DU_LOG("\nERROR --> SCTP : Invalid notification type\n");
490 }/* End of sctpNtfyHdlr */
492 /*******************************************************************
494 * @brief Receives message on the socket
498 * Function : sctpSockPoll
501 * Receives message on the socket
504 * @return ROK - success
507 * ****************************************************************/
508 uint8_t sctpSockPoll()
510 uint8_t assocIdx = 0, destIdx = 0;
513 uint32_t *timeoutPtr;
516 CmInetMemInfo memInfo;
517 sctpSockPollParams pollParams;
518 uint64_t numMsgRcvd = 0;
521 memset(&pollParams, 0, sizeof(sctpSockPollParams));
524 /* All sockets are non-blocking */
526 timeoutPtr = &timeout;
527 memInfo.region = CU_APP_MEM_REG;
528 memInfo.pool = CU_POOL;
530 CM_INET_FD_ZERO(&pollParams.readFd);
534 /* Receiving SCTP data */
535 for(assocIdx = 0; assocIdx < sctpCb.numAssoc; assocIdx++)
537 if((ret = processPolling(&pollParams, &sctpCb.assocCb[assocIdx], timeoutPtr, &memInfo)) != ROK)
539 DU_LOG("\nERROR --> SCTP : Failed to RecvMsg for F1 at CU\n");
543 /* Receiving EGTP data */
545 ret = cmInetRecvMsg(&(egtpCb.sockFd), &fromAddr, &memInfo, &egtpBuf, &egtpBufLen, CM_INET_NO_FLAG);
546 if(ret == ROK && egtpBuf != NULLP)
548 for(destIdx = 0; destIdx < egtpCb.numDu; destIdx++)
550 if((fromAddr.port == egtpCb.dstCb[destIdx].dstAddr.port) && (fromAddr.address == egtpCb.dstCb[destIdx].dstAddr.address))
552 DU_LOG("\nINFO --> EGTP : Received UL Message [%ld] from DU Id [%d]\n", numMsgRcvd+1, egtpCb.dstCb[destIdx].duId);
554 //ODU_PRINT_MSG(egtpBuf, 0 ,0);
555 cuEgtpHdlRecvMsg(egtpBuf);
563 }/* End of sctpSockPoll() */
565 /*******************************************************************
567 * @brief checks for valid readFd and process the InetSctpRecvMsg
572 * Function : processPolling
575 * checks for valid readFd and process the InetSctpRecvMsg
578 * @params[in] Params required for polling
579 * @params[in] SockFd for file descriptor
580 * @params[in] timeoutPtr indicates the timeout value
581 * @params[in] MemInfo indicates memory region
583 * @return ROK - success
586 * ****************************************************************/
588 uint8_t processPolling(sctpSockPollParams *pollParams, CuSctpAssocCb *assocCb, uint32_t *timeoutPtr, CmInetMemInfo *memInfo)
591 CM_INET_FD_SET(&assocCb->sockFd, &pollParams->readFd);
592 ret = cmInetSelect(&pollParams->readFd, NULLP, timeoutPtr, &pollParams->numFd);
593 if(CM_INET_FD_ISSET(&assocCb->sockFd, &pollParams->readFd))
595 CM_INET_FD_CLR(&assocCb->sockFd, &pollParams->readFd);
596 ret = cmInetSctpRecvMsg(&assocCb->sockFd, &pollParams->addr, &pollParams->port, memInfo, &pollParams->mBuf, \
597 &pollParams->bufLen, &pollParams->info, &pollParams->flag, &pollParams->ntfy);
598 if(assocCb->connUp & (ret != ROK))
600 assocCb->bReadFdSet = RFAILED;
604 if(((pollParams->flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0) && (ret == ROK))
606 ret = sctpNtfyHdlr(assocCb, &pollParams->ntfy);
609 DU_LOG("\nERROR --> SCTP : Failed to process sctp notify msg\n");
612 else if(assocCb->connUp && assocCb->intf == F1_INTERFACE)
614 F1APMsgHdlr(&assocCb->destId, pollParams->mBuf);
615 ODU_PUT_MSG_BUF(pollParams->mBuf);
617 else if(assocCb->connUp && assocCb->intf == XN_INTERFACE)
619 DU_LOG("\nDEBUG --> SCTP : Received message at XN interface");
620 ODU_PRINT_MSG(pollParams->mBuf, 0,0);
621 XNAPMsgHdlr(&assocCb->destId, pollParams->mBuf);
622 ODU_PUT_MSG_BUF(pollParams->mBuf);
626 ODU_PUT_MSG_BUF(pollParams->mBuf);
631 }/* End of sctpSockPoll() */
633 /*******************************************************************
635 * @brief Send message on an SCTP Association
639 * Function : sendOnSctpAssoc
642 * Send message on SCTP association
645 * @return ROK - success
648 * ****************************************************************/
649 uint8_t sendOnSctpAssoc(CuSctpAssocCb *assocCb, Buffer *mBuf)
652 MsgLen len = 0; /* number of actually sent octets */
653 CmInetMemInfo memInfo;
655 memset(&memInfo , 0, sizeof(CmInetMemInfo));
656 memInfo.region = CU_APP_MEM_REG;
657 memInfo.pool = CU_POOL;
659 ret = cmInetSctpSendMsg(&assocCb->sockFd, &assocCb->destIpNetAddr, assocCb->destPort, &memInfo, mBuf, &len, 0, \
660 FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
662 if(ret != ROK && ret != RWOULDBLOCK)
664 DU_LOG("\nERROR --> SCTP : Send message failed");
670 /*******************************************************************
672 * @brief Send message on SCTP socket
676 * Function : sctpSend
679 * Send message on SCTP socket
682 * @return ROK - success
685 * ****************************************************************/
686 uint8_t sctpSend(InterfaceType intf, uint32_t destId, Buffer *mBuf)
688 uint8_t assocIdx = 0;
690 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
692 if((sctpCb.assocCb[assocIdx].intf == intf) && (sctpCb.assocCb[assocIdx].destId == destId))
694 if(sendOnSctpAssoc(&sctpCb.assocCb[assocIdx], mBuf) == ROK)
700 DU_LOG("\nERROR --> SCTP : Dest ID [%d] at Interface [%d] not found in SCTP DestCb list. Failed to send message", destId, intf);
702 } /* End of sctpSend */
704 /**********************************************************************
706 **********************************************************************/