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