a0a455a4b9a4ac0d46ac81d27a76e89e6e5dfd3d
[o-du/l2.git] / src / ric_stub / ric_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 "ric_stub_sctp.h"
23 #include "ric_stub.h"
24 #include "ric_e2ap_msg_hdl.h"
25 #include "E2AP-PDU.h"
26
27 uint8_t   socket_type;
28 SctpGlobalCb sctpCb;
29
30 /**************************************************************************
31  * @brief Function to configure the Sctp Params during config Request
32  *
33  * @details
34  *
35  *      Function : sctpCfgReq
36  * 
37  *      Functionality:
38  *           This function configures SCTP Params during the config Request
39  *     
40  * @return ROK     - success
41  *         RFAILED - failure
42  *
43  ***************************************************************************/
44
45 uint8_t sctpCfgReq()
46 {
47    int destIdx = 0, assocIdx = 0;
48
49    sctpCb.sctpCfg = ricCb.ricCfgParams.sctpParams;   
50    fillAddrLst(&sctpCb.localAddrLst, &sctpCb.sctpCfg.localIpAddr);
51    memset(&sctpCb.e2LstnSockFd, -1, sizeof(CmInetFd));
52    for(destIdx=0; destIdx < sctpCb.sctpCfg.numDestNode; destIdx++)
53    {   
54       sctpCb.assocCb[assocIdx].destPort = sctpCb.sctpCfg.destCb[destIdx].destPort;
55       sctpCb.assocCb[assocIdx].bReadFdSet = ROK;
56       memset(&sctpCb.assocCb[assocIdx].sockFd, -1, sizeof(CmInetFd));
57       fillDestNetAddr(&sctpCb.assocCb[assocIdx].destIpNetAddr, &sctpCb.sctpCfg.destCb[destIdx].destIpAddr);
58       sctpCb.assocCb[assocIdx].connUp = false;
59       assocIdx++;
60    }   
61    sctpCb.numAssoc = assocIdx;
62    return ROK;
63 }
64
65 /*******************************************************************
66  *
67  * @brief Fills the address List of the source Ip Address
68  *
69  * @details
70  *
71  *    Function : fillAddrLst
72  *
73  *    Functionality:
74  *       Fills the address List of source Ip Address
75  *
76  * @params[in] CmInetNetAddrLst *addrLstPtr, Address List pointer
77  * @params[in] F1IpAddr *srcIpAddr, src Ip Adrress to be filled in the Address List
78  * @return ROK     - success
79  *         RFAILED - failure
80  *
81  ******************************************************************/
82
83 uint8_t fillAddrLst(CmInetNetAddrLst *addrLstPtr, SctpIpAddr *ipAddr)
84
85    addrLstPtr->addrs[addrLstPtr->count].type = CM_INET_IPV4ADDR_TYPE;
86    addrLstPtr->addrs[addrLstPtr->count].u.ipv4NetAddr = CM_INET_NTOH_UINT32(ipAddr->ipV4Addr);
87    addrLstPtr->count++;
88
89    return ROK;
90 }
91
92 /******************************************************************************
93  *
94  * @brief Fills the address List of the source Ip Address
95  *
96  * @details
97  *
98  *    Function : fillDestNetAddr
99  *
100  *    Functionality:
101  *       Fills the address List of destinatoion Ip Address
102  *
103  * @params[in] CmInetNetAddr *destAddrPtr, Address List pointer
104  * @params[in] F1IpAddr *dstIpAddr, destIp Address to be filled in the Address List
105  * @return ROK     - success
106  *         RFAILED - failure
107  *
108  *******************************************************************************/
109 uint8_t fillDestNetAddr(CmInetNetAddr *destAddrPtr, SctpIpAddr *dstIpPtr)
110 {
111    /* Filling destination address */
112    destAddrPtr->type = CM_INET_IPV4ADDR_TYPE;
113    destAddrPtr->u.ipv4NetAddr = CM_INET_NTOH_UINT32(dstIpPtr->ipV4Addr);
114    return ROK;
115 }
116
117 /******************************************************************************
118  *
119  * @brief Eastablishes the Assoc Req for the received interface type
120  *
121  * @details
122  *
123  *    Function : sctpStartReq
124  *
125  *    Functionality:
126  *       Eastablishes the Assoc Req for the received interface type
127  *
128  * @params[in] DuSctpDestCb *paramPtr
129  * @return ROK     - success
130  *         RFAILED - failure
131  *
132  *******************************************************************************/
133
134 uint8_t sctpStartReq()
135 {
136    uint8_t assocIdx  = 0;
137    uint8_t ret = ROK;
138
139    socket_type = CM_INET_STREAM;
140
141    if(sctpCb.numAssoc)
142    {
143
144       if((ret = cmInetSocket(socket_type, &sctpCb.e2LstnSockFd, IPPROTO_SCTP) != ROK))
145       {
146          DU_LOG("\nERROR  -->  SCTP : Socket[%d] coudnt open for listening", sctpCb.e2LstnSockFd.fd);
147       } 
148       else if((ret = cmInetSctpBindx(&sctpCb.e2LstnSockFd, &sctpCb.localAddrLst, sctpCb.sctpCfg.e2SctpPort)) != ROK)
149       {
150          DU_LOG("\nERROR  -->  SCTP: Binding failed at RIC");
151       }
152       else if((ret = cmInetListen(&sctpCb.e2LstnSockFd, 1)) != ROK)
153       {
154          DU_LOG("\nERROR  -->  SCTP: Unable to accept the connection at CU");
155          DU_LOG("\nERROR  -->  SCTP : Listening on socket failed");
156          cmInetClose(&sctpCb.e2LstnSockFd);
157          return RFAILED;
158       }
159       else
160       {
161          for(assocIdx=0; assocIdx < sctpCb.numAssoc; assocIdx++)
162          {
163             if((ret = sctpAccept(&sctpCb.assocCb[assocIdx])) != ROK)
164             {
165                DU_LOG("\nERROR  -->  SCTP: Unable to accept the connection at RIC");
166             }
167          }
168       }
169    }
170
171    if(ret == ROK)
172    {
173       if(sctpSockPoll() != ROK)
174       {
175          DU_LOG("\nERROR  -->  SCTP: Polling failed to start at RIC");
176       }
177    }
178    return (ret);
179 }
180
181 /*******************************************************************
182  *
183  * @brief Sets socket options as per requirement
184  *
185  * @details
186  *
187  *    Function : sctpSetSockOpts
188  *
189  *    Functionality: 
190  *       Sets socket options as per requirement
191  *
192  * @params[in] 
193  * @return ROK     - success
194  *         RFAILED - failure
195  *
196  * ****************************************************************/
197 uint8_t sctpSetSockOpts(CmInetFd *sock_Fd)
198 {
199    S16 ret = ROK;
200    CmSctpEvent sctpEvent;
201   
202    sctpEvent.dataIoEvent          = TRUE;
203    sctpEvent.associationEvent     = TRUE;
204    sctpEvent.addressEvent         = TRUE;
205    sctpEvent.sendFailureEvent     = TRUE;
206    sctpEvent.peerErrorEvent       = TRUE;
207    sctpEvent.shutdownEvent        = TRUE;
208    sctpEvent.partialDeliveryEvent = TRUE;
209    sctpEvent.adaptationLayerEvent = TRUE;
210
211    if((ret = cmInetSetOpt(sock_Fd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent)) != ROK)
212    {
213      ret = RFAILED;
214    }
215   
216    return (ret);
217 }
218
219 /*******************************************************************
220  *
221  * @brief Initiates connection with peer SCTP
222  *
223  * @details
224  *
225  *    Function : sctpAccept
226  *
227  *    Functionality:
228  *       Establishes SCTP connection with peer.
229  *       Here, DU-SCTP will initate connection towards RIC-SCTP
230  *
231  * @params[in] 
232  * @return ROK     - success
233  *         RFAILED - failure
234  *
235  * ****************************************************************/
236 uint8_t sctpAccept(RicSctpAssocCb *assocCb)
237 {
238    uint8_t  ret;
239
240    DU_LOG("\nINFO   -->  SCTP : Connecting");
241
242    while(!assocCb->connUp)
243    {
244       ret = cmInetAccept(&sctpCb.e2LstnSockFd, &assocCb->peerAddr, &assocCb->sockFd);
245       if (ret == ROKDNA)
246       {
247          continue;
248       }
249       else if(ret != ROK)
250       {
251          DU_LOG("\nERROR  -->  SCTP : Failed to accept connection");
252          return RFAILED;
253       }
254       else
255       {
256          assocCb->connUp = TRUE;
257          sctpSetSockOpts(&assocCb->sockFd);
258          break;
259       }
260    }
261    DU_LOG("\nINFO   -->  SCTP : Connection established");
262
263    return ROK;
264 }
265
266 /*******************************************************************
267  *
268  * @brief Handles an SCTP notification message
269  *
270  * @details
271  *
272  *    Function : sctpNtfyHdlr
273  *
274  *    Functionality:
275  *      Handles an SCTP notification message
276  *
277  * @params[in] Notify message
278  *
279  * @return ROK     - success
280  *         RFAILED - failure
281  *
282  * ****************************************************************/
283 uint8_t sctpNtfyHdlr(RicSctpAssocCb *assocCb, CmInetSctpNotification *ntfy)
284 {
285    switch(ntfy->header.nType)
286    {
287       case CM_INET_SCTP_ASSOC_CHANGE :
288          DU_LOG("\nINFO   -->  SCTP : Assoc change notification received");
289          switch(ntfy->u.assocChange.state)
290          {
291             case CM_INET_SCTP_COMM_UP:
292                DU_LOG("\nINFO   -->  Event : COMMUNICATION UP");
293                assocCb->connUp = TRUE;
294                break;
295             case CM_INET_SCTP_COMM_LOST:
296                DU_LOG("\nINFO   -->  Event : COMMUNICATION LOST");
297                assocCb->connUp = FALSE;
298                break;
299             case CM_INET_SCTP_RESTART:
300                DU_LOG("\nINFO   -->  Event : SCTP RESTART");
301                assocCb->connUp = FALSE;
302                break;
303             case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */
304                DU_LOG("\nINFO   -->  Event : SHUTDOWN COMPLETE");
305                assocCb->connUp = FALSE;
306                break;
307             case CM_INET_SCTP_CANT_STR_ASSOC:
308                DU_LOG("\nINFO   -->  Event : CANT START ASSOC");
309                assocCb->connUp = FALSE;
310                break;
311             default:
312                DU_LOG("\nERROR   -->  Invalid event");
313                break;
314          }
315          break;
316       case CM_INET_SCTP_PEER_ADDR_CHANGE :
317          DU_LOG("\nINFO   -->  SCTP : Peer Address Change notificarion received");
318          /* Need to add handler */
319          break;
320       case CM_INET_SCTP_REMOTE_ERROR :
321          DU_LOG("\nINFO   -->  SCTP : Remote Error notification received");
322          break;
323       case CM_INET_SCTP_SEND_FAILED :
324          DU_LOG("\nINFO   -->  SCTP : Send Failed notification received\n");
325          break;
326       case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */
327          DU_LOG("\nINFO   -->  SCTP : Shutdown Event notification received\n");
328          assocCb->connUp = FALSE;
329          deleteE2NodeInfo(&ricCb.duInfo[0]);
330          exit(0);
331          break;
332       case CM_INET_SCTP_ADAPTATION_INDICATION :
333          DU_LOG("\nINFO   -->  SCTP : Adaptation Indication received\n");
334          break;
335       case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
336          DU_LOG("\nINFO   -->  SCTP : Partial Delivery Event received\n");
337          break;
338       default:
339          DU_LOG("\nERROR   -->  SCTP : Invalid notification type\n");
340          break;
341    }
342
343    sctpNtfyInd(ntfy);
344    return ROK;
345 }/* End of sctpNtfyHdlr */
346
347 /*******************************************************************
348  *
349  * @brief Receives message on the socket
350  *
351  * @details
352  *
353  *    Function : sctpSockPoll
354  *
355  *    Functionality:
356  *      Receives message on the socket
357  *
358  * @params[in] 
359  * @return ROK     - success
360  *         RFAILED - failure
361  *
362  * ****************************************************************/
363 uint8_t sctpSockPoll()
364 {
365    uint8_t            assocIdx;
366    uint16_t           ret = ROK;
367    uint32_t           timeout;
368    uint32_t           *timeoutPtr;
369    CmInetMemInfo      memInfo;
370    sctpSockPollParams e2PollParams;
371
372    memset(&e2PollParams, 0, sizeof(sctpSockPollParams));
373     
374    /* All sockets are non-blocking */
375    timeout = 0;
376    timeoutPtr = &timeout;
377    memInfo.region = RIC_APP_MEM_REG;
378    memInfo.pool   = RIC_POOL;
379
380    CM_INET_FD_ZERO(&e2PollParams.readFd);
381
382    DU_LOG("\nINFO  -->  SCTP : Polling started at RIC\n");
383    while(1)
384    {
385       /* Receiving SCTP data */
386       for(assocIdx = 0; assocIdx < sctpCb.numAssoc; assocIdx++)
387       {
388          if((ret = processPolling(&e2PollParams, &sctpCb.assocCb[assocIdx], timeoutPtr, &memInfo)) != ROK)
389          {
390             DU_LOG("\nERROR  -->  SCTP : Failed to RecvMsg for E2 at RIC \n");
391          }
392       }
393    };
394    return (ret);
395 }/* End of sctpSockPoll() */
396
397 /*******************************************************************
398  *
399  * @brief checks for valid readFd and process the InetSctpRecvMsg
400  * during polling 
401  *
402  * @details
403  *
404  *    Function : processPolling
405  *
406  *    Functionality:
407  *         checks for valid readFd and process the InetSctpRecvMsg
408  *         during polling
409  *
410  * @params[in]  Params required for polling
411  * @params[in]  SockFd for file descriptor
412  * @params[in]  timeoutPtr indicates the timeout value
413  * @params[in]  MemInfo indicates memory region
414  *
415  * @return ROK     - success
416  *         RFAILED - failure
417  *
418  * ****************************************************************/
419
420  
421 uint8_t processPolling(sctpSockPollParams *pollParams, RicSctpAssocCb *assocCb, uint32_t *timeoutPtr, CmInetMemInfo *memInfo)
422 {
423    uint16_t ret = ROK;
424
425    CM_INET_FD_SET(&assocCb->sockFd, &pollParams->readFd);
426    ret = cmInetSelect(&pollParams->readFd, NULLP, timeoutPtr, &pollParams->numFd);
427    if(CM_INET_FD_ISSET(&assocCb->sockFd, &pollParams->readFd))
428    {
429       CM_INET_FD_CLR(&assocCb->sockFd, &pollParams->readFd);
430       ret = cmInetSctpRecvMsg(&assocCb->sockFd, &pollParams->addr, &pollParams->port, memInfo, &pollParams->mBuf, \
431           &pollParams->bufLen, &pollParams->info, &pollParams->flag, &pollParams->ntfy);
432       if(assocCb->connUp & (ret != ROK))
433       {
434          assocCb->bReadFdSet = RFAILED;
435       }
436       else
437       {
438          if(((pollParams->flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0) && (ret == ROK))
439          {
440             ret = sctpNtfyHdlr(assocCb, &pollParams->ntfy);
441             if(ret != ROK)
442             {
443                DU_LOG("\nERROR  -->  SCTP : Failed to process sctp notify msg\n");
444             }
445          }
446          else if(assocCb->connUp)
447          {  
448             E2APMsgHdlr(&assocCb->duId, pollParams->mBuf);
449             ODU_PUT_MSG_BUF(pollParams->mBuf);
450          }
451          else
452          {
453             ODU_PUT_MSG_BUF(pollParams->mBuf);
454          }
455       } 
456   }
457   return ROK;
458 }/* End of sctpSockPoll() */
459
460 /*******************************************************************
461  *
462  * @brief Send message on SCTP socket
463  *
464  * @details
465  *
466  *    Function : sctpSend 
467  *
468  *    Functionality:
469  *        Send message on SCTP socket
470  *
471  * @params[in] 
472  * @return ROK     - success
473  *         RFAILED - failure
474  *
475  * ****************************************************************/
476 uint8_t sctpSend(uint32_t duId, Buffer *mBuf)
477 {
478    uint8_t          assocIdx;
479    uint8_t          ret;
480    MsgLen           len;          /* number of actually sent octets */
481    CmInetMemInfo    memInfo;                        
482    
483    memInfo.region = RIC_APP_MEM_REG;               
484    memInfo.pool   = RIC_POOL;
485
486    for(assocIdx = 0; assocIdx < sctpCb.numAssoc; assocIdx++)
487    {
488       if(sctpCb.assocCb[assocIdx].duId == duId)
489       {
490          ret = cmInetSctpSendMsg(&sctpCb.assocCb[assocIdx].sockFd, &sctpCb.assocCb[assocIdx].destIpNetAddr, \
491                sctpCb.assocCb[assocIdx].destPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
492
493          if(ret != ROK && ret != RWOULDBLOCK)
494          {
495             DU_LOG("\nERROR  -->  SCTP : Send message failed");
496             return RFAILED;
497          }
498       }
499    }
500    return ROK;
501 } /* End of sctpSend */
502 /**********************************************************************
503          End of file
504 **********************************************************************/