[Issue-ID : ODUHIGH-487] EGTP Port fix at F1 interface
[o-du/l2.git] / src / cu_stub / cu_stub_sctp.c
1 /*******************************************************************************
2 ################################################################################
3 #   Copyright (c) [2017-2019] [Radisys]                                        #
4 #                                                                              #
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                                    #
8 #                                                                              #
9 #       http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                              #
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 *******************************************************************************/
18
19 /* This file contains all SCTP related functionality */
20
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"
26 #include "cu_stub.h"
27 #include "cm_inet.h"
28 #include "cm_tpt.h"
29
30 #include "cm_inet.x"
31 #include "cm_tpt.x"
32
33
34 /**************************************************************************
35  * @brief Task Initiation callback function. 
36  *
37  * @details
38  *
39  *     Function : sctpActvInit 
40  *    
41  *     Functionality:
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.
45  *     
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 
49  *              usage of this task.
50  * @param[in]  Reason reason.
51  * @return ROK     - success
52  *         RFAILED - failure
53  ***************************************************************************/
54 uint8_t sctpActvInit()
55 {
56    DU_LOG("\n\nDEBUG  -->  SCTP : Initializing");
57    memset(&sctpCb, 0, sizeof(SctpGlobalCb));
58    sctpCb.sctpCfg = cuCb.cuCfgParams.sctpParams;
59    return ROK;
60 }
61
62 /**************************************************************************
63  * @brief Task Activation callback function. 
64  *
65  * @details
66  *
67  *      Function : sctpActvTsk 
68  * 
69  *      Functionality:
70  *           This function handles all SCTP messages received
71  *           This API is registered with SSI during the 
72  *           Task Registration of DU APP.
73  *     
74  * @param[in]  Pst     *pst, Post structure of the primitive.     
75  * @param[in]  Buffer *mBuf, Packed primitive parameters in the
76  *  buffer.
77  * @return ROK     - success
78  *         RFAILED - failure
79  *
80  ***************************************************************************/
81 uint8_t sctpActvTsk(Pst *pst, Buffer *mBuf)
82 {
83
84 //TODO: TBD
85    return ROK;
86 }
87
88 /**************************************************************************
89  * @brief Function to configure the Sctp Params during config Request
90  *
91  * @details
92  *
93  *      Function : duSctpCfgReq
94  * 
95  *      Functionality:
96  *           This function configures SCTP Params during the config Request
97  *     
98  * @return ROK     - success
99  *         RFAILED - failure
100  *
101  ***************************************************************************/
102
103 uint8_t sctpCfgReq()
104 {
105    int destIdx = 0, assocIdx = 0;
106    
107    fillAddrLst(&sctpCb.localAddrLst, &sctpCb.sctpCfg.localIpAddr);
108    memset(&sctpCb.f1LstnSockFd, -1, sizeof(CmInetFd));
109
110    for(destIdx=0; destIdx < sctpCb.sctpCfg.numDestNode; destIdx++)
111    {
112       sctpCb.assocCb[assocIdx].destPort = sctpCb.sctpCfg.destCb[destIdx].destPort;
113       sctpCb.assocCb[assocIdx].bReadFdSet = ROK;
114       memset(&sctpCb.assocCb[assocIdx].sockFd, -1, sizeof(CmInetFd));
115       fillDestNetAddr(&sctpCb.assocCb[assocIdx].destIpNetAddr, &sctpCb.sctpCfg.destCb[destIdx].destIpAddr);
116       assocIdx++;
117    }
118    sctpCb.numAssoc = assocIdx;
119    return ROK;
120 }
121
122
123 /*******************************************************************
124  *
125  * @brief Fills the address List of the source Ip Address
126  *
127  * @details
128  *
129  *    Function : fillAddrLst
130  *
131  *    Functionality:
132  *       Fills the address List of source Ip Address
133  *
134  * @params[in] CmInetNetAddrLst *addrLstPtr, Address List pointer
135  * @params[in] F1IpAddr *srcIpAddr, src Ip Adrress to be filled in the Address List
136  * @return ROK     - success
137  *         RFAILED - failure
138  *
139  ******************************************************************/
140
141 uint8_t fillAddrLst(CmInetNetAddrLst *addrLstPtr, SctpIpAddr *ipAddr)
142
143    addrLstPtr->addrs[addrLstPtr->count].type = CM_INET_IPV4ADDR_TYPE;
144    addrLstPtr->addrs[addrLstPtr->count].u.ipv4NetAddr = CM_INET_NTOH_UINT32(ipAddr->ipV4Addr);
145    addrLstPtr->count++;
146    return ROK;
147 }
148
149 /******************************************************************************
150  *
151  * @brief Fills the address List of the source Ip Address
152  *
153  * @details
154  *
155  *    Function : fillDestNetAddr
156  *
157  *    Functionality:
158  *       Fills the address List of destinatoion Ip Address
159  *
160  * @params[in] CmInetNetAddr *destAddrPtr, Address List pointer
161  * @params[in] F1IpAddr *dstIpAddr, destIp Address to be filled in the Address List
162  * @return ROK     - success
163  *         RFAILED - failure
164  *
165  *******************************************************************************/
166 uint8_t fillDestNetAddr(CmInetNetAddr *destAddrPtr, SctpIpAddr *dstIpPtr)
167 {
168    /* Filling destination address */
169    destAddrPtr->type = CM_INET_IPV4ADDR_TYPE;
170    destAddrPtr->u.ipv4NetAddr = CM_INET_NTOH_UINT32(dstIpPtr->ipV4Addr);
171    return ROK;
172 }
173
174 /******************************************************************************
175  *
176  * @brief Eastablishes the Assoc Req for the received interface type
177  *
178  * @details
179  *
180  *    Function : sctpStartReq
181  *
182  *    Functionality:
183  *       Eastablishes the Assoc Req for the received interface type
184  *
185  * @params[in] DuSctpDestCb *paramPtr
186  * @return ROK     - success
187  *         RFAILED - failure
188  *
189  *******************************************************************************/
190
191 uint8_t sctpStartReq()
192 {
193    uint8_t assocIdx;
194    uint8_t ret = ROK;
195
196    socket_type = CM_INET_STREAM;
197
198    if(sctpCb.numAssoc)
199    {
200       if((ret = cmInetSocket(socket_type, &sctpCb.f1LstnSockFd, IPPROTO_SCTP) != ROK))
201       {
202          DU_LOG("\nERROR  -->  SCTP : Socket[%d] coudnt open for listening", sctpCb.f1LstnSockFd.fd);
203       } 
204       else if((ret = cmInetSctpBindx(&sctpCb.f1LstnSockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.f1SctpPort)) != ROK)
205       {
206          DU_LOG("\nERROR  -->  SCTP: Binding failed at CU");
207       }
208       else if(ret = cmInetListen(&sctpCb.f1LstnSockFd, 1) != ROK)
209       {
210          DU_LOG("\nERROR  -->  SCTP : Listening on socket failed");
211          cmInetClose(&sctpCb.f1LstnSockFd);
212          return RFAILED;
213       }
214       else
215       {
216          for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
217          {
218             if((ret = sctpAccept(&sctpCb.assocCb[assocIdx])) != ROK)
219             {
220                DU_LOG("\nERROR  -->  SCTP: Unable to accept the connection at CU");
221             }
222          }
223       }
224    }
225
226    if(ret == ROK)
227    {
228       if(sctpSockPoll() != ROK)
229       {
230          DU_LOG("\nERROR  -->  SCTP: Polling failed to start at CU");
231       }
232    }
233    return (ret);
234 }
235 /*******************************************************************
236  *
237  * @brief Sets socket options as per requirement
238  *
239  * @details
240  *
241  *    Function : sctpSetSockOpts
242  *
243  *    Functionality: 
244  *       Sets socket options as per requirement
245  *
246  * @params[in] 
247  * @return ROK     - success
248  *         RFAILED - failure
249  *
250  * ****************************************************************/
251 uint8_t sctpSetSockOpts(CmInetFd *sock_Fd)
252 {
253    S16 ret = ROK;
254    CmSctpEvent sctpEvent;
255   
256    sctpEvent.dataIoEvent          = TRUE;
257    sctpEvent.associationEvent     = TRUE;
258    sctpEvent.addressEvent         = TRUE;
259    sctpEvent.sendFailureEvent     = TRUE;
260    sctpEvent.peerErrorEvent       = TRUE;
261    sctpEvent.shutdownEvent        = TRUE;
262    sctpEvent.partialDeliveryEvent = TRUE;
263    sctpEvent.adaptationLayerEvent = TRUE;
264
265    if((ret = cmInetSetOpt(sock_Fd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent)) != ROK)
266    {
267      ret = RFAILED;
268    }
269   
270    return (ret);
271 }
272
273 /*******************************************************************
274  *
275  * @brief Initiates connection with peer SCTP
276  *
277  * @details
278  *
279  *    Function : sctpAccept
280  *
281  *    Functionality:
282  *       Establishes SCTP connection with peer.
283  *       Here, DU-SCTP will initate connection towards CU-SCTP
284  *
285  * @params[in] 
286  * @return ROK     - success
287  *         RFAILED - failure
288  *
289  * ****************************************************************/
290 uint8_t sctpAccept(CuSctpAssocCb *assocCb)
291 {
292    uint8_t  ret;
293
294    DU_LOG("\nINFO  -->  SCTP : Connecting");
295
296    while(!assocCb->connUp)
297    {
298       ret = cmInetAccept(&sctpCb.f1LstnSockFd, &assocCb->peerAddr, &assocCb->sockFd);
299       if (ret == ROKDNA)
300       {
301          continue;
302       }
303       else if(ret != ROK)
304       {
305          DU_LOG("\nERROR  -->  SCTP : Failed to accept connection");
306          return RFAILED;
307       }
308       else
309       {
310          assocCb->connUp = TRUE;
311          sctpSetSockOpts(&assocCb->sockFd);
312          break;
313       }
314    }
315    DU_LOG("\nINFO  -->  SCTP : Connection established");
316
317    return ROK;
318 }
319
320 /*******************************************************************
321  *
322  * @brief Handles an SCTP notification message
323  *
324  * @details
325  *
326  *    Function : sctpNtfyHdlr
327  *
328  *    Functionality:
329  *      Handles an SCTP notification message
330  *
331  * @params[in] Notify message
332  *
333  * @return ROK     - success
334  *         RFAILED - failure
335  *
336  * ****************************************************************/
337 uint8_t sctpNtfyHdlr(CuSctpAssocCb *assocCb, CmInetSctpNotification *ntfy)
338 {
339    switch(ntfy->header.nType)
340    {
341       case CM_INET_SCTP_ASSOC_CHANGE :
342          DU_LOG("\nINFO  -->  SCTP : Assoc change notification received");
343          switch(ntfy->u.assocChange.state)
344          {
345             case CM_INET_SCTP_COMM_UP:
346                DU_LOG("DEBUG  -->  Event : COMMUNICATION UP");
347                assocCb->connUp = TRUE;
348                break;
349             case CM_INET_SCTP_COMM_LOST:
350                DU_LOG("DEBUG  -->  Event : COMMUNICATION LOST");
351                assocCb->connUp = FALSE;
352                break;
353             case CM_INET_SCTP_RESTART:
354                DU_LOG("DEBUG  -->  Event : SCTP RESTART");
355                assocCb->connUp = FALSE;
356                break;
357             case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */
358                DU_LOG("DEBUG  -->  Event : SHUTDOWN COMPLETE");
359                assocCb->connUp = FALSE;
360                break;
361             case CM_INET_SCTP_CANT_STR_ASSOC:
362                DU_LOG("DEBUG  -->  Event : CANT START ASSOC");
363                assocCb->connUp = FALSE;
364                break;
365             default:
366                DU_LOG("\nERROR  -->  Invalid event");
367                break;
368          }
369          break;
370       case CM_INET_SCTP_PEER_ADDR_CHANGE :
371          DU_LOG("\nINFO  -->  SCTP : Peer Address Change notificarion received");
372          /* Need to add handler */
373          break;
374       case CM_INET_SCTP_REMOTE_ERROR :
375          DU_LOG("\nINFO  -->  SCTP : Remote Error notification received");
376          break;
377       case CM_INET_SCTP_SEND_FAILED :
378          DU_LOG("\nINFO  -->  SCTP : Send Failed notification received\n");
379          break;
380       case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */
381          DU_LOG("\nINFO  -->  SCTP : Shutdown Event notification received\n");
382          assocCb->connUp = FALSE;
383          exit(0);
384          break;
385       case CM_INET_SCTP_ADAPTATION_INDICATION :
386          DU_LOG("\nINFO  -->  SCTP : Adaptation Indication received\n");
387          break;
388       case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
389          DU_LOG("\nINFO  -->  SCTP : Partial Delivery Event received\n");
390          break;
391       default:
392          DU_LOG("\nERROR  -->  SCTP : Invalid notification type\n");
393          break;
394    }
395
396    sctpNtfyInd(ntfy);
397    return ROK;
398 }/* End of sctpNtfyHdlr */
399
400 /*******************************************************************
401  *
402  * @brief Receives message on the socket
403  *
404  * @details
405  *
406  *    Function : sctpSockPoll
407  *
408  *    Functionality:
409  *      Receives message on the socket
410  *
411  * @params[in] 
412  * @return ROK     - success
413  *         RFAILED - failure
414  *
415  * ****************************************************************/
416 uint8_t sctpSockPoll()
417 {
418    uint8_t       assocIdx = 0, destIdx = 0;
419    uint16_t      ret = ROK;
420    uint32_t      timeout;
421    uint32_t      *timeoutPtr;
422    Buffer        *egtpBuf;
423    MsgLen        egtpBufLen;
424    CmInetMemInfo memInfo;
425    sctpSockPollParams f1PollParams;
426    uint64_t      numMsgRcvd = 0;
427    CmInetAddr    fromAddr;
428
429    memset(&f1PollParams, 0, sizeof(sctpSockPollParams));
430     
431
432    /* All sockets are non-blocking */
433    timeout = 0;
434    timeoutPtr = &timeout;
435    memInfo.region = CU_APP_MEM_REG;
436    memInfo.pool   = CU_POOL;
437    
438    CM_INET_FD_ZERO(&f1PollParams.readFd);
439
440    while(1)
441    {
442       /* Receiving SCTP data */
443       for(assocIdx = 0; assocIdx < sctpCb.numAssoc; assocIdx++)
444       {
445          if((ret = processPolling(&f1PollParams, &sctpCb.assocCb[assocIdx], timeoutPtr, &memInfo)) != ROK)
446          {
447             DU_LOG("\nERROR  -->  SCTP : Failed to RecvMsg for F1 at CU\n");
448          }
449       }
450
451       /* Receiving EGTP data */
452       egtpBufLen = -1;
453       ret = cmInetRecvMsg(&(egtpCb.sockFd), &fromAddr, &memInfo, &egtpBuf, &egtpBufLen, CM_INET_NO_FLAG);
454       if(ret == ROK && egtpBuf != NULLP)
455       {
456          for(destIdx = 0; destIdx < egtpCb.numDu; destIdx++)
457          {
458             if((fromAddr.port == egtpCb.dstCb[destIdx].dstAddr.port) && (fromAddr.address == egtpCb.dstCb[destIdx].dstAddr.address))
459             {
460                DU_LOG("\nINFO  -->  EGTP : Received UL Message [%ld] from DU Id [%d]\n", numMsgRcvd+1, egtpCb.dstCb[destIdx].duId);
461                numMsgRcvd++;
462                //ODU_PRINT_MSG(egtpBuf, 0 ,0);
463                cuEgtpHdlRecvMsg(egtpBuf);
464                break;
465             }
466
467          }
468       }
469    };
470    return (ret);
471 }/* End of sctpSockPoll() */
472
473 /*******************************************************************
474  *
475  * @brief checks for valid readFd and process the InetSctpRecvMsg
476  * during polling 
477  *
478  * @details
479  *
480  *    Function : processPolling
481  *
482  *    Functionality:
483  *         checks for valid readFd and process the InetSctpRecvMsg
484  *         during polling
485  *
486  * @params[in]  Params required for polling
487  * @params[in]  SockFd for file descriptor
488  * @params[in]  timeoutPtr indicates the timeout value
489  * @params[in]  MemInfo indicates memory region
490  *
491  * @return ROK     - success
492  *         RFAILED - failure
493  *
494  * ****************************************************************/
495
496 uint8_t processPolling(sctpSockPollParams *pollParams, CuSctpAssocCb *assocCb, uint32_t *timeoutPtr, CmInetMemInfo *memInfo)
497 {
498    uint16_t ret = ROK;
499    CM_INET_FD_SET(&assocCb->sockFd, &pollParams->readFd);
500    ret = cmInetSelect(&pollParams->readFd, NULLP, timeoutPtr, &pollParams->numFd);
501    if(CM_INET_FD_ISSET(&assocCb->sockFd, &pollParams->readFd))
502    {
503       CM_INET_FD_CLR(&assocCb->sockFd, &pollParams->readFd);
504       ret = cmInetSctpRecvMsg(&assocCb->sockFd, &pollParams->addr, &pollParams->port, memInfo, &pollParams->mBuf, \
505          &pollParams->bufLen, &pollParams->info, &pollParams->flag, &pollParams->ntfy);
506       if(assocCb->connUp & (ret != ROK))
507       {
508          assocCb->bReadFdSet = RFAILED;
509       }
510       else
511       {
512          if(((pollParams->flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0) && (ret == ROK))
513          {
514             ret = sctpNtfyHdlr(assocCb, &pollParams->ntfy);
515             if(ret != ROK)
516             {
517                DU_LOG("\nERROR  -->  SCTP : Failed to process sctp notify msg\n");
518             }
519          }
520          else if(assocCb->connUp)
521          {  
522             F1APMsgHdlr(&assocCb->duId, pollParams->mBuf);
523             ODU_PUT_MSG_BUF(pollParams->mBuf);
524          }
525          else
526          {
527             ODU_PUT_MSG_BUF(pollParams->mBuf);
528          }
529       } 
530   }
531   return ROK;
532 }/* End of sctpSockPoll() */
533
534 /*******************************************************************
535  *
536  * @brief Send message on SCTP socket
537  *
538  * @details
539  *
540  *    Function : sctpSend 
541  *
542  *    Functionality:
543  *        Send message on SCTP socket
544  *
545  * @params[in] 
546  * @return ROK     - success
547  *         RFAILED - failure
548  *
549  * ****************************************************************/
550 uint8_t sctpSend(uint32_t duId, Buffer *mBuf)
551 {
552    uint8_t          ret = ROK, assocIdx = 0;
553    MsgLen           len = 0;          /* number of actually sent octets */
554    CmInetMemInfo    memInfo;                        
555   
556    memset(&memInfo , 0, sizeof(CmInetMemInfo));
557    memInfo.region = CU_APP_MEM_REG;               
558    memInfo.pool   = CU_POOL;
559
560    for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
561    {
562       if(sctpCb.assocCb[assocIdx].duId == duId)
563       {
564          ret = cmInetSctpSendMsg(&sctpCb.assocCb[assocIdx].sockFd, &sctpCb.assocCb[assocIdx].destIpNetAddr, \
565                   sctpCb.assocCb[assocIdx].destPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
566
567          if(ret != ROK && ret != RWOULDBLOCK)
568          {
569             DU_LOG("\nERROR  -->  SCTP : Send message failed");
570             return RFAILED;
571          }
572          return ROK;
573       }
574    }
575    DU_LOG("\nERROR  -->  SCTP : DU ID [%d] not found in SCTP DestCb list. Failed to send message", duId);
576    return RFAILED;
577 } /* End of sctpSend */
578
579 /**********************************************************************
580          End of file
581 **********************************************************************/