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"
35 /**************************************************************************
36 * @brief Task Initiation callback function.
40 * Function : sctpActvInit
43 * This function is supplied as one of parameters during SCTP's
44 * task registration. SSI will invoke this function once, after
45 * it creates and attaches this TAPA Task to a system task.
47 * @param[in] Ent entity, the entity ID of this task.
48 * @param[in] Inst inst, the instance ID of this task.
49 * @param[in] Region region, the region ID registered for memory
51 * @param[in] Reason reason.
52 * @return ROK - success
54 ***************************************************************************/
55 uint8_t sctpActvInit()
57 DU_LOG("\n\nDEBUG --> SCTP : Initializing");
58 memset(&sctpCb, 0, sizeof(SctpGlobalCb));
59 sctpCb.sctpCfg = cuCb.cuCfgParams.sctpParams;
63 /**************************************************************************
64 * @brief Task Activation callback function.
68 * Function : sctpActvTsk
71 * This function handles all SCTP messages received
72 * This API is registered with SSI during the
73 * Task Registration of DU APP.
75 * @param[in] Pst *pst, Post structure of the primitive.
76 * @param[in] Buffer *mBuf, Packed primitive parameters in the
78 * @return ROK - success
81 ***************************************************************************/
82 uint8_t sctpActvTsk(Pst *pst, Buffer *mBuf)
89 /**************************************************************************
90 * @brief Function to configure the Sctp Params during config Request
94 * Function : duSctpCfgReq
97 * This function configures SCTP Params during the config Request
99 * @return ROK - success
102 ***************************************************************************/
106 int destIdx = 0, assocIdx = 0;
108 fillAddrLst(&sctpCb.localAddrLst, &sctpCb.sctpCfg.localIpAddr);
109 memset(&sctpCb.f1LstnSockFd, -1, sizeof(CmInetFd));
111 for(destIdx=0; destIdx < sctpCb.sctpCfg.f1SctpInfo.numDestNode; destIdx++)
113 sctpCb.assocCb[assocIdx].intf = F1_INTERFACE;
114 sctpCb.assocCb[assocIdx].destPort = sctpCb.sctpCfg.f1SctpInfo.destCb[destIdx].destPort;
115 sctpCb.assocCb[assocIdx].bReadFdSet = ROK;
116 memset(&sctpCb.assocCb[assocIdx].sockFd, -1, sizeof(CmInetFd));
117 fillDestNetAddr(&sctpCb.assocCb[assocIdx].destIpNetAddr, &sctpCb.sctpCfg.f1SctpInfo.destCb[destIdx].destIpAddr);
121 sctpCb.localXnNodeType = sctpCb.sctpCfg.xnSctpInfo.localNodeType;
122 for(destIdx=0; destIdx < sctpCb.sctpCfg.xnSctpInfo.numDestNode; destIdx++)
124 sctpCb.assocCb[assocIdx].intf = XN_INTERFACE;
125 sctpCb.assocCb[assocIdx].destPort = sctpCb.sctpCfg.xnSctpInfo.destCb[destIdx].destPort;
126 sctpCb.assocCb[assocIdx].bReadFdSet = ROK;
127 memset(&sctpCb.assocCb[assocIdx].sockFd, -1, sizeof(CmInetFd));
128 fillDestNetAddr(&sctpCb.assocCb[assocIdx].destIpNetAddr, &sctpCb.sctpCfg.xnSctpInfo.destCb[destIdx].destIpAddr);
131 sctpCb.numAssoc = assocIdx;
136 /*******************************************************************
138 * @brief Fills the address List of the source Ip Address
142 * Function : fillAddrLst
145 * Fills the address List of source Ip Address
147 * @params[in] CmInetNetAddrLst *addrLstPtr, Address List pointer
148 * @params[in] F1IpAddr *srcIpAddr, src Ip Adrress to be filled in the Address List
149 * @return ROK - success
152 ******************************************************************/
154 uint8_t fillAddrLst(CmInetNetAddrLst *addrLstPtr, SctpIpAddr *ipAddr)
156 addrLstPtr->addrs[addrLstPtr->count].type = CM_INET_IPV4ADDR_TYPE;
157 addrLstPtr->addrs[addrLstPtr->count].u.ipv4NetAddr = CM_INET_NTOH_UINT32(ipAddr->ipV4Addr);
162 /******************************************************************************
164 * @brief Fills the address List of the source Ip Address
168 * Function : fillDestNetAddr
171 * Fills the address List of destinatoion Ip Address
173 * @params[in] CmInetNetAddr *destAddrPtr, Address List pointer
174 * @params[in] F1IpAddr *dstIpAddr, destIp Address to be filled in the Address List
175 * @return ROK - success
178 *******************************************************************************/
179 uint8_t fillDestNetAddr(CmInetNetAddr *destAddrPtr, SctpIpAddr *dstIpPtr)
181 /* Filling destination address */
182 destAddrPtr->type = CM_INET_IPV4ADDR_TYPE;
183 destAddrPtr->u.ipv4NetAddr = CM_INET_NTOH_UINT32(dstIpPtr->ipV4Addr);
187 /******************************************************************************
189 * @brief Eastablishes the Assoc Req for the received interface type
193 * Function : sctpStartReq
196 * Eastablishes the Assoc Req for the received interface type
198 * @params[in] DuSctpDestCb *paramPtr
199 * @return ROK - success
202 *******************************************************************************/
204 uint8_t sctpStartReq()
210 socket_type = CM_INET_STREAM;
212 /* Establish SCTP association at XN interface */
213 if(sctpCb.sctpCfg.xnSctpInfo.numDestNode)
215 if(sctpCb.localXnNodeType == SERVER)
217 if((ret = cmInetSocket(socket_type, &sctpCb.xnLstnSockFd, IPPROTO_SCTP) != ROK))
219 DU_LOG("\nERROR --> SCTP : Socket[%d] coudnt open for listening", sctpCb.f1LstnSockFd.fd);
221 else if((ret = cmInetSctpBindx(&sctpCb.xnLstnSockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.xnSctpInfo.port)) != ROK)
223 DU_LOG("\nERROR --> SCTP: Binding failed at CU");
225 else if(ret = cmInetListen(&sctpCb.xnLstnSockFd, 1) != ROK)
227 DU_LOG("\nERROR --> SCTP : Listening on socket failed");
228 cmInetClose(&sctpCb.xnLstnSockFd);
233 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
235 if(sctpCb.assocCb[assocIdx].intf == XN_INTERFACE)
237 if((ret = sctpAccept(&sctpCb.xnLstnSockFd, &sctpCb.assocCb[assocIdx])) != ROK)
239 DU_LOG("\nERROR --> SCTP: Unable to accept the connection at CU");
245 else if(sctpCb.localXnNodeType == CLIENT)
247 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
249 if(sctpCb.assocCb[assocIdx].intf == XN_INTERFACE)
251 if((ret = cmInetSocket(socket_type, &sctpCb.assocCb[assocIdx].sockFd, IPPROTO_SCTP)) != ROK)
253 DU_LOG("\nERROR --> SCTP : Failed while opening a socket in ODU");
255 else if((ret = cmInetSctpBindx(&sctpCb.assocCb[assocIdx].sockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.xnSctpInfo.port)) != ROK)
257 DU_LOG("\nERROR --> SCTP: Failed during Binding in ODU");
259 else if((ret = sctpSetSockOpts(&sctpCb.assocCb[assocIdx].sockFd)) != ROK)
261 DU_LOG("\nERROR --> SCTP : Failed to set Socket Opt in ODU");
267 DU_LOG("\nERROR --> SCTP : Failed while establishing Req at DU");
272 ret = cmInetSctpConnectx(&sctpCb.assocCb[assocIdx].sockFd, &sctpCb.assocCb[assocIdx].destIpNetAddr, \
273 &sctpCb.assocCb[assocIdx].destAddrLst, sctpCb.assocCb[assocIdx].destPort);
274 /* 115 error_code indicates that Operation is in progress and hence ignored if SctpConnect failed due to this */
286 /* Establish SCTP association at F1 interface */
287 if(sctpCb.sctpCfg.f1SctpInfo.numDestNode)
289 if((ret = cmInetSocket(socket_type, &sctpCb.f1LstnSockFd, IPPROTO_SCTP) != ROK))
291 DU_LOG("\nERROR --> SCTP : Socket[%d] coudnt open for listening", sctpCb.f1LstnSockFd.fd);
293 else if((ret = cmInetSctpBindx(&sctpCb.f1LstnSockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.f1SctpInfo.port)) != ROK)
295 DU_LOG("\nERROR --> SCTP: Binding failed at CU");
297 else if(ret = cmInetListen(&sctpCb.f1LstnSockFd, 1) != ROK)
299 DU_LOG("\nERROR --> SCTP : Listening on socket failed");
300 cmInetClose(&sctpCb.f1LstnSockFd);
305 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
307 if(sctpCb.assocCb[assocIdx].intf == F1_INTERFACE)
309 if((ret = sctpAccept(&sctpCb.f1LstnSockFd, &sctpCb.assocCb[assocIdx])) != ROK)
311 DU_LOG("\nERROR --> SCTP: Unable to accept the connection at CU");
320 if(sctpSockPoll() != ROK)
322 DU_LOG("\nERROR --> SCTP: Polling failed to start at CU");
328 /*******************************************************************
330 * @brief Sets socket options as per requirement
334 * Function : sctpSetSockOpts
337 * Sets socket options as per requirement
340 * @return ROK - success
343 * ****************************************************************/
344 uint8_t sctpSetSockOpts(CmInetFd *sock_Fd)
347 CmSctpEvent sctpEvent;
349 sctpEvent.dataIoEvent = TRUE;
350 sctpEvent.associationEvent = TRUE;
351 sctpEvent.addressEvent = TRUE;
352 sctpEvent.sendFailureEvent = TRUE;
353 sctpEvent.peerErrorEvent = TRUE;
354 sctpEvent.shutdownEvent = TRUE;
355 sctpEvent.partialDeliveryEvent = TRUE;
356 sctpEvent.adaptationLayerEvent = TRUE;
358 if((ret = cmInetSetOpt(sock_Fd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent)) != ROK)
366 /*******************************************************************
368 * @brief Initiates connection with peer SCTP
372 * Function : sctpAccept
375 * Establishes SCTP connection with peer.
376 * Here, DU-SCTP will initate connection towards CU-SCTP
379 * @return ROK - success
382 * ****************************************************************/
383 uint8_t sctpAccept(CmInetFd *lstnSockFd, CuSctpAssocCb *assocCb)
387 DU_LOG("\nINFO --> SCTP : Connecting");
389 while(!assocCb->connUp)
391 ret = cmInetAccept(lstnSockFd, &assocCb->peerAddr, &assocCb->sockFd);
398 DU_LOG("\nERROR --> SCTP : Failed to accept connection");
403 assocCb->connUp = TRUE;
404 sctpSetSockOpts(&assocCb->sockFd);
408 DU_LOG("\nINFO --> SCTP : Connection established");
413 /*******************************************************************
415 * @brief Handles an SCTP notification message
419 * Function : sctpNtfyHdlr
422 * Handles an SCTP notification message
424 * @params[in] Notify message
426 * @return ROK - success
429 * ****************************************************************/
430 uint8_t sctpNtfyHdlr(CuSctpAssocCb *assocCb, CmInetSctpNotification *ntfy)
432 switch(ntfy->header.nType)
434 case CM_INET_SCTP_ASSOC_CHANGE :
435 DU_LOG("\nINFO --> SCTP : Assoc change notification received");
436 switch(ntfy->u.assocChange.state)
438 case CM_INET_SCTP_COMM_UP:
439 DU_LOG("DEBUG --> Event : COMMUNICATION UP");
440 assocCb->connUp = TRUE;
442 case CM_INET_SCTP_COMM_LOST:
443 DU_LOG("DEBUG --> Event : COMMUNICATION LOST");
444 assocCb->connUp = FALSE;
446 case CM_INET_SCTP_RESTART:
447 DU_LOG("DEBUG --> Event : SCTP RESTART");
448 assocCb->connUp = FALSE;
450 case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */
451 DU_LOG("DEBUG --> Event : SHUTDOWN COMPLETE");
452 assocCb->connUp = FALSE;
454 case CM_INET_SCTP_CANT_STR_ASSOC:
455 DU_LOG("DEBUG --> Event : CANT START ASSOC");
456 assocCb->connUp = FALSE;
459 DU_LOG("\nERROR --> Invalid event");
463 case CM_INET_SCTP_PEER_ADDR_CHANGE :
464 DU_LOG("\nINFO --> SCTP : Peer Address Change notificarion received");
465 /* Need to add handler */
467 case CM_INET_SCTP_REMOTE_ERROR :
468 DU_LOG("\nINFO --> SCTP : Remote Error notification received");
470 case CM_INET_SCTP_SEND_FAILED :
471 DU_LOG("\nINFO --> SCTP : Send Failed notification received\n");
473 case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */
474 DU_LOG("\nINFO --> SCTP : Shutdown Event notification received\n");
475 assocCb->connUp = FALSE;
478 case CM_INET_SCTP_ADAPTATION_INDICATION :
479 DU_LOG("\nINFO --> SCTP : Adaptation Indication received\n");
481 case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
482 DU_LOG("\nINFO --> SCTP : Partial Delivery Event received\n");
485 DU_LOG("\nERROR --> SCTP : Invalid notification type\n");
491 }/* End of sctpNtfyHdlr */
493 /*******************************************************************
495 * @brief Receives message on the socket
499 * Function : sctpSockPoll
502 * Receives message on the socket
505 * @return ROK - success
508 * ****************************************************************/
509 uint8_t sctpSockPoll()
511 uint8_t assocIdx = 0, destIdx = 0;
514 uint32_t *timeoutPtr;
517 CmInetMemInfo memInfo;
518 sctpSockPollParams pollParams;
519 uint64_t numMsgRcvd = 0;
522 memset(&pollParams, 0, sizeof(sctpSockPollParams));
525 /* All sockets are non-blocking */
527 timeoutPtr = &timeout;
528 memInfo.region = CU_APP_MEM_REG;
529 memInfo.pool = CU_POOL;
531 CM_INET_FD_ZERO(&pollParams.readFd);
535 /* Receiving SCTP data */
536 for(assocIdx = 0; assocIdx < sctpCb.numAssoc; assocIdx++)
538 if((ret = processPolling(&pollParams, &sctpCb.assocCb[assocIdx], timeoutPtr, &memInfo)) != ROK)
540 DU_LOG("\nERROR --> SCTP : Failed to RecvMsg for F1 at CU\n");
544 /* Receiving EGTP data */
546 ret = cmInetRecvMsg(&(egtpCb.sockFd), &fromAddr, &memInfo, &egtpBuf, &egtpBufLen, CM_INET_NO_FLAG);
547 if(ret == ROK && egtpBuf != NULLP)
549 for(destIdx = 0; destIdx < egtpCb.numDu; destIdx++)
551 if((fromAddr.port == egtpCb.dstCb[destIdx].dstAddr.port) && (fromAddr.address == egtpCb.dstCb[destIdx].dstAddr.address))
553 DU_LOG("\nINFO --> EGTP : Received UL Message [%ld] from DU Id [%d]\n", numMsgRcvd+1, egtpCb.dstCb[destIdx].duId);
555 //ODU_PRINT_MSG(egtpBuf, 0 ,0);
556 cuEgtpHdlRecvMsg(egtpBuf);
564 }/* End of sctpSockPoll() */
566 /*******************************************************************
568 * @brief checks for valid readFd and process the InetSctpRecvMsg
573 * Function : processPolling
576 * checks for valid readFd and process the InetSctpRecvMsg
579 * @params[in] Params required for polling
580 * @params[in] SockFd for file descriptor
581 * @params[in] timeoutPtr indicates the timeout value
582 * @params[in] MemInfo indicates memory region
584 * @return ROK - success
587 * ****************************************************************/
589 uint8_t processPolling(sctpSockPollParams *pollParams, CuSctpAssocCb *assocCb, uint32_t *timeoutPtr, CmInetMemInfo *memInfo)
592 CM_INET_FD_SET(&assocCb->sockFd, &pollParams->readFd);
593 ret = cmInetSelect(&pollParams->readFd, NULLP, timeoutPtr, &pollParams->numFd);
594 if(CM_INET_FD_ISSET(&assocCb->sockFd, &pollParams->readFd))
596 CM_INET_FD_CLR(&assocCb->sockFd, &pollParams->readFd);
597 ret = cmInetSctpRecvMsg(&assocCb->sockFd, &pollParams->addr, &pollParams->port, memInfo, &pollParams->mBuf, \
598 &pollParams->bufLen, &pollParams->info, &pollParams->flag, &pollParams->ntfy);
599 if(assocCb->connUp & (ret != ROK))
601 assocCb->bReadFdSet = RFAILED;
605 if(((pollParams->flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0) && (ret == ROK))
607 ret = sctpNtfyHdlr(assocCb, &pollParams->ntfy);
610 DU_LOG("\nERROR --> SCTP : Failed to process sctp notify msg\n");
613 else if(assocCb->connUp && assocCb->intf == F1_INTERFACE)
615 F1APMsgHdlr(&assocCb->destId, pollParams->mBuf);
616 ODU_PUT_MSG_BUF(pollParams->mBuf);
618 else if(assocCb->connUp && assocCb->intf == XN_INTERFACE)
620 DU_LOG("\nDEBUG --> SCTP : Received message at XN interface");
621 ODU_PRINT_MSG(pollParams->mBuf, 0,0);
622 XNAPMsgHdlr(&assocCb->destId, pollParams->mBuf);
623 ODU_PUT_MSG_BUF(pollParams->mBuf);
627 ODU_PUT_MSG_BUF(pollParams->mBuf);
632 }/* End of sctpSockPoll() */
634 /*******************************************************************
636 * @brief Send message on an SCTP Association
640 * Function : sendOnSctpAssoc
643 * Send message on SCTP association
646 * @return ROK - success
649 * ****************************************************************/
650 uint8_t sendOnSctpAssoc(CuSctpAssocCb *assocCb, Buffer *mBuf)
653 MsgLen len = 0; /* number of actually sent octets */
654 CmInetMemInfo memInfo;
656 memset(&memInfo , 0, sizeof(CmInetMemInfo));
657 memInfo.region = CU_APP_MEM_REG;
658 memInfo.pool = CU_POOL;
660 ret = cmInetSctpSendMsg(&assocCb->sockFd, &assocCb->destIpNetAddr, assocCb->destPort, &memInfo, mBuf, &len, 0, \
661 FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
663 if(ret != ROK && ret != RWOULDBLOCK)
665 DU_LOG("\nERROR --> SCTP : Send message failed");
671 /*******************************************************************
673 * @brief Send message on SCTP socket
677 * Function : sctpSend
680 * Send message on SCTP socket
683 * @return ROK - success
686 * ****************************************************************/
687 uint8_t sctpSend(InterfaceType intf, uint32_t destId, Buffer *mBuf)
689 uint8_t assocIdx = 0;
691 for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
693 if((sctpCb.assocCb[assocIdx].intf == intf) && (sctpCb.assocCb[assocIdx].destId == destId))
695 if(sendOnSctpAssoc(&sctpCb.assocCb[assocIdx], mBuf) == ROK)
701 DU_LOG("\nERROR --> SCTP : Dest ID [%d] at Interface [%d] not found in SCTP DestCb list. Failed to send message", destId, intf);
703 } /* End of sctpSend */
705 /**********************************************************************
707 **********************************************************************/