Initial commit for Bronze release
[o-du/l2.git] / src / du_app / du_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 <stdio.h> 
22 #include "du_sctp.h"
23 #include "lsctp.h"
24
25 /* Global variable declaration */
26 F1SctpParams sctpCfg;            /* SCTP configurations at DU */
27
28 /**************************************************************************
29  * @brief Task Initiation callback function. 
30  *
31  * @details
32  *
33  *     Function : sctpActvInit 
34  *    
35  *     Functionality:
36  *             This function is supplied as one of parameters during SCTP's 
37  *             task registration. SSI will invoke this function once, after
38  *             it creates and attaches this TAPA Task to a system task.
39  *     
40  * @param[in]  Ent entity, the entity ID of this task.     
41  * @param[in]  Inst inst, the instance ID of this task.
42  * @param[in]  Region region, the region ID registered for memory 
43  *              usage of this task.
44  * @param[in]  Reason reason.
45  * @return ROK     - success
46  *         RFAILED - failure
47  ***************************************************************************/
48 S16 sctpActvInit(Ent entity, Inst inst, Region region, Reason reason)
49 {
50    DU_LOG("\n\nSCTP : Initializing");
51    SSetProcId(DU_PROC);
52    connUp = FALSE;
53    assocId = 0;
54    nonblocking = FALSE;
55    return ROK;
56
57 }
58
59 /**************************************************************************
60  * @brief Task Activation callback function. 
61  *
62  * @details
63  *
64  *      Function : sctpActvTsk 
65  * 
66  *      Functionality:
67  *           This function handles all SCTP messages received
68  *           This API is registered with SSI during the 
69  *           Task Registration of DU APP.
70  *     
71  * @param[in]  Pst     *pst, Post structure of the primitive.     
72  * @param[in]  Buffer *mBuf, Packed primitive parameters in the
73  *  buffer.
74  * @return ROK     - success
75  *         RFAILED - failure
76  *
77  ***************************************************************************/
78 S16 sctpActvTsk(Pst *pst, Buffer *mBuf)
79 {
80    switch(pst->srcEnt)
81    {
82       case ENTDUAPP:
83          {
84             switch(pst->event)
85             {
86                case EVTSCTPSTRT:
87                {
88                   cmUnpkSctpAssocReq(mBuf);
89                   SPutMsg(mBuf);
90                   sctpAssocReq();
91                   break;
92                }
93             }
94             break;
95          }
96    }
97    SExitTsk();
98    return ROK;
99 }
100
101 /*******************************************************************
102  *
103  * @brief Opens a non-blocking socket and binds to local address
104  *
105  * @details
106  *
107  *    Function : openSctpEndp
108  *
109  *    Functionality:
110  *         Opens a non-blocking socket and binds to local address
111  *
112  * @params[in] 
113  * @return ROK     - success
114  *         RFAILED - failure
115  *
116  * ****************************************************************/
117 S16 openSctpEndp()
118 {
119    U8 ret;
120    U8 numRetry = 0;
121
122    /* Opening a non-blocking SCTP socket */
123    socket_type = CM_INET_STREAM;
124
125    do{
126       ret = cmInetSocket(socket_type, &sockFd, IPPROTO_SCTP);
127       if (ret != ROK)
128       {
129          numRetry++;
130          if(numRetry >= MAX_RETRY)
131          {
132             DU_LOG("\nSCTP : All attempts to open socket failed.");
133             /* Send indication to du_app */
134             RETVALUE(RFAILED);
135          }
136          else
137          {
138             DU_LOG("\nSCTP : Retrying socket opening"); 
139          }
140       }
141       else
142       {
143          DU_LOG("\nSCTP : Socket[%d] open",sockFd.fd);
144          break;
145       }
146    }while(numRetry < MAX_RETRY);
147
148    RETVALUE(ROK);
149 } /* End of openSctpEndp */
150
151
152 /*******************************************************************
153  *
154  * @brief Bind socket to local Ip address and port
155  *
156  * @details
157  *
158  *    Function : bindSctpEndp
159  *
160  *    Functionality:
161  *      -Bind socket to local Ip address and port
162  *
163  * @params[in] 
164  * @return ROK     - success
165  *         RFAILED - failure
166  *
167  * ****************************************************************/
168 S16 bindSctpEndp()
169 {
170
171    U8 ret;
172    U8 numRetry = 0;
173
174    /* Binding the socket with local address */
175    localAddrLst.count = 1;
176    if(sctpCfg.duIpAddr.ipV4Pres)
177    {
178       localAddrLst.addrs[0].type = CM_INET_IPV4ADDR_TYPE;
179       localAddrLst.addrs[0].u.ipv4NetAddr = CM_INET_NTOH_U32(sctpCfg.duIpAddr.ipV4Addr);
180    }
181    else
182    {
183       localAddrLst.addrs[0].type = CM_INET_IPV4ADDR_TYPE;
184       localAddrLst.addrs[0].u.ipv4NetAddr = 0;
185    } 
186
187    do{
188       ret = cmInetSctpBindx(&sockFd, &localAddrLst, sctpCfg.duPort);
189       if (ret != ROK)
190       {
191          numRetry++;
192          if(numRetry >= MAX_RETRY)
193          {
194             DU_LOG("\nSCTP : All attempts to bind socket failed.");
195             cmInetClose(&sockFd);
196             /* Send indication to du_app */
197             RETVALUE(RFAILED);
198          }
199          else
200          {
201             DU_LOG("\nSCTP : Retrying socket binding");
202          }
203       }
204       else
205       {
206          DU_LOG("\nSCTP : Socket bind successful");
207          break;
208       }
209    }while(numRetry < MAX_RETRY);
210
211   RETVALUE(ROK);
212
213 } /* End of bindSctpEndp() */
214
215 /*******************************************************************
216  *
217  * @brief Sets socket options as per requirement
218  *
219  * @details
220  *
221  *    Function : sctpSetSockOpts
222  *
223  *    Functionality: 
224  *       Sets socket options as per requirement
225  *
226  * @params[in] 
227  * @return ROK     - success
228  *         RFAILED - failure
229  *
230  * ****************************************************************/
231 S16 sctpSetSockOpts()
232 {
233    CmSctpEvent sctpEvent;
234
235    sctpEvent.dataIoEvent          = TRUE;
236    sctpEvent.associationEvent     = TRUE;
237    sctpEvent.addressEvent         = TRUE;
238    sctpEvent.sendFailureEvent     = TRUE;
239    sctpEvent.peerErrorEvent       = TRUE;
240    sctpEvent.shutdownEvent        = TRUE;
241    sctpEvent.partialDeliveryEvent = TRUE;
242    sctpEvent.adaptationLayerEvent = TRUE;
243
244    cmInetSetOpt(&sockFd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent);
245    RETVALUE(ROK);
246
247    RETVALUE(ROK);
248 }
249
250 /*******************************************************************
251  *
252  * @brief Initiates connection with peer SCTP
253  *
254  * @details
255  *
256  *    Function : sctpConnect
257  *
258  *    Functionality:
259  *       Establishes SCTP connection with peer.
260  *       Here, DU-SCTP will initate connection towards CU-SCTP
261  *
262  * @params[in] 
263  * @return ROK     - success
264  *         RFAILED - failure
265  *
266  * ****************************************************************/
267 S16 sctpConnect()
268 {
269    U8  ret;
270    U8  numRetry = 0;
271    CmInetNetAddr  primDstAddr; /* primary destination address */
272
273    /* Filling primary destination address */
274    if(sctpCfg.cuIpAddr.ipV4Pres)
275    {
276       primDstAddr.type = CM_INET_IPV4ADDR_TYPE;
277       primDstAddr.u.ipv4NetAddr = CM_INET_NTOH_U32(sctpCfg.cuIpAddr.ipV4Addr);
278    }
279    else
280    {
281       primDstAddr.type = CM_INET_IPV4ADDR_TYPE;
282       primDstAddr.u.ipv4NetAddr = 0;
283    }
284
285    /* Filling destination address list */
286    remoteAddrLst.count = 1;
287    if(sctpCfg.cuIpAddr.ipV4Pres)
288    {
289       remoteAddrLst.addrs[0].type = CM_INET_IPV4ADDR_TYPE;
290       remoteAddrLst.addrs[0].u.ipv4NetAddr = CM_INET_NTOH_U32(sctpCfg.cuIpAddr.ipV4Addr);
291    }
292    else
293    {
294       remoteAddrLst.addrs[0].type = CM_INET_IPV4ADDR_TYPE;
295       remoteAddrLst.addrs[0].u.ipv4NetAddr = 0;
296    }
297
298    /* Sending connect request to remote */
299    do{
300       ret = cmInetSctpConnectx(&sockFd, &primDstAddr, &remoteAddrLst, sctpCfg.cuPort);
301       if (ret == RFAILED || ret == ROKDNA || ret == RCLOSED)
302       {
303          numRetry++;
304          if(numRetry >= MAX_RETRY)
305          {
306             DU_LOG("\nSCTP : All attempts to connect failed.");
307             cmInetClose(&sockFd);
308             /* Send indication to du_app */
309             RETVALUE(RFAILED);
310          }
311          else
312          {
313             DU_LOG("\nSCTP : Retrying connection");
314          }
315       }
316       else if(ret == RINPROGRESS)
317       {
318          DU_LOG("\nSCTP : Connection in progess");
319          break;
320       }
321       else
322       {
323          connUp = TRUE;
324          DU_LOG("\nSCTP : Connect successful");
325          break;
326       }
327    }while(numRetry < MAX_RETRY);
328
329    RETVALUE(ROK);
330 }/* End of sctpConnect() */
331
332 /*******************************************************************
333  *
334  * @brief Post received data/notification to DU APP 
335  *
336  * @details
337  *
338  *    Function : sendToDuApp 
339  *
340  *    Functionality:
341  *         Post received data/notification to DU APP
342  *
343  * @params[in]  Message buffer
344  *              Message event
345  *
346  * @return ROK     - success
347  *         RFAILED - failure
348  *
349  * ****************************************************************/
350 void sendToDuApp(Buffer *mBuf, Event event)
351 {
352    Pst pst;
353    DU_LOG("\nSCTP : Forwarding received message to duApp");
354    SPrntMsg(mBuf, 0, 0);
355
356
357    cmMemset((U8 *)&(pst), 0, sizeof(Pst));
358    pst.srcEnt = (Ent)ENTSCTP;
359    pst.srcInst = (Inst)SCTP_INST;
360    pst.srcProcId = DU_PROC;
361    pst.dstEnt = (Ent)ENTDUAPP;
362    pst.dstInst = (Inst)DU_INST;
363    pst.dstProcId = pst.srcProcId;
364    pst.event = event;
365    pst.selector = DU_SELECTOR_LC;
366    pst.pool= DU_POOL;
367    pst.region = DFLT_REGION;
368
369    if (SPstTsk(&pst, mBuf) != ROK)
370    {
371       DU_LOG("\nSCTP : SPstTsk failed in duReadCfg");
372    }
373 }
374
375 /*******************************************************************
376  *
377  * @brief Handles an SCTP notification message
378  *
379  * @Sending *
380  *    Function : sctpNtfyHdlr
381  *
382  *    Functionality:
383  *      Handles an SCTP notification message
384  *
385  * @params[in] Notify message
386  *
387  * @return ROK     - success
388  *         RFAILED - failure
389  *
390  * ****************************************************************/
391 S16 sctpNtfyHdlr(CmInetSctpNotification *ntfy)
392 {
393    Pst pst;
394
395    switch(ntfy->header.nType)
396    {
397       case CM_INET_SCTP_ASSOC_CHANGE :
398          DU_LOG("\nSCTP : Assoc change notification received");
399          switch(ntfy->u.assocChange.state)
400          {
401             case CM_INET_SCTP_COMM_UP:
402                DU_LOG("Event : COMMUNICATION UP");
403                connUp = TRUE;
404                break;
405             case CM_INET_SCTP_COMM_LOST:
406                DU_LOG("Event : COMMUNICATION LOST");
407                connUp = FALSE;
408                break;
409             case CM_INET_SCTP_RESTART:
410                DU_LOG("Event : SCTP RESTART");
411                connUp = FALSE;
412                break;
413             case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */
414                DU_LOG("Event : SHUTDOWN COMPLETE");
415                connUp = FALSE;
416                break;
417             case CM_INET_SCTP_CANT_STR_ASSOC:
418                DU_LOG("Event : CANT START ASSOC");
419                connUp = FALSE;
420                break;
421             default:
422                DU_LOG("\nInvalid event");
423                break;
424          }
425          break;
426       case CM_INET_SCTP_PEER_ADDR_CHANGE :
427          DU_LOG("\nSCTP : Peer Address Change notificarion received");
428          /* Need to add handler */
429          break;
430       case CM_INET_SCTP_REMOTE_ERROR :
431          DU_LOG("\nSCTP : Remote Error notification received");
432          break;
433       case CM_INET_SCTP_SEND_FAILED :
434          DU_LOG("\nSCTP : Send Failed notification received\n");
435          break;
436       case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */
437          DU_LOG("\nSCTP : Shutdown Event notification received\n");
438          connUp = FALSE;
439          break;
440       case CM_INET_SCTP_ADAPTATION_INDICATION :
441          DU_LOG("\nSCTP : Adaptation Indication received\n");
442          break;
443       case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
444          DU_LOG("\nSCTP : Partial Delivery Event received\n");
445          break;
446       default:
447          DU_LOG("\nSCTP : Invalid sctp notification type\n");
448          break;
449    }
450
451    /* Pack notification and send to APP */
452    DU_LOG("\nSCTP : Forwarding received message to duApp");
453     
454    cmMemset((U8 *)&(pst), 0, sizeof(Pst));
455    pst.srcEnt = (Ent)ENTSCTP;
456    pst.srcInst = (Inst)SCTP_INST;
457    pst.srcProcId = DU_PROC;
458    pst.dstEnt = (Ent)ENTDUAPP;
459    pst.dstInst = (Inst)DU_INST;
460    pst.dstProcId = pst.srcProcId;
461    pst.event = EVTSCTPNTFY;
462    pst.selector = DU_SELECTOR_LC;
463    pst.pool= DU_POOL;
464    pst.region = DFLT_REGION;
465
466    if(cmPkSctpNtfy(&pst, ntfy) != ROK)
467    {
468       DU_LOG("\nSCTP : Failed to pack SCTP notification");
469       RETVALUE(RFAILED);
470    }
471    RETVALUE(ROK);
472 }
473
474 /*******************************************************************
475  *
476  * @brief Receives message on the socket
477  *
478  * @details
479  *
480  *    Function : sctpSockPoll
481  *
482  *    Functionality:
483  *      Receives message on the socket
484  *
485  * @params[in] 
486  * @return ROK     - success
487  *         RFAILED - failure
488  *
489  * ****************************************************************/
490 S16 sctpSockPoll()
491 {
492    U8   ret;
493    S16  numFds;
494    CmInetFdSet   readFd;
495    U16           port;
496    U32           timeout;           /* timeout for cmInetSelect() */
497    U32           *timeoutPtr;        /* pointer to timeout */
498    U32            flag;
499    Buffer        *mBuf;
500    MsgLen        bufLen;
501    CmInetMemInfo memInfo;      /* buffer allocation info */
502    CmInetNetAddr addr;
503    CmInetSctpSndRcvInfo   info;
504    CmInetSctpNotification ntfy;
505
506    if (sockFd.blocking)
507    {
508       /* blocking */
509       timeoutPtr = NULLP;
510    }
511    else
512    {
513       /* non-blocking */
514       timeout = 0;
515       timeoutPtr = &timeout;
516    }
517    memInfo.region = DU_APP_MEM_REGION;
518    memInfo.pool   = DU_POOL;
519    CM_INET_FD_ZERO(&readFd);
520
521    while(1)
522    {
523       CM_INET_FD_SET(&sockFd, &readFd);
524       ret = cmInetSelect(&readFd, NULLP, timeoutPtr, &numFds);
525       if (CM_INET_FD_ISSET(&sockFd, &readFd))
526       {
527          CM_INET_FD_CLR(&sockFd, &readFd);
528          ret = cmInetSctpRecvMsg(&sockFd, &addr, &port, &memInfo, &mBuf, &bufLen, &info, &flag, &ntfy);
529          if (connUp && ret != ROK)
530          {
531             DU_LOG("\nFailed to receive sctp msg\n");
532          }
533          else
534          {
535             /* If SCTP notification received */
536             if ((flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0)
537             {
538                ret = sctpNtfyHdlr(&ntfy);
539                if(ret != ROK)
540                {
541                   DU_LOG("\nSCTP : Failed to process sctp notify msg\n");
542                }
543             }
544             else if(connUp) /* If data received */
545             {
546                sendToDuApp(mBuf, EVTSCTPDATA);
547             }
548             else
549             {
550                SPutMsg(mBuf);
551             }
552          }
553       }
554    };
555
556    RETVALUE(ROK);
557 }/* End of sctpSockPoll() */
558
559 /*******************************************************************
560  *
561  * @brief Send message on SCTP socket
562  *
563  * @details
564  *
565  *    Function : sctpSend 
566  *
567  *    Functionality:
568  *        Send message on SCTP socket
569  *
570  * @params[in] 
571  * @return ROK     - success
572  *         RFAILED - failure
573  *
574  * ****************************************************************/
575 S16 sctpSend(Buffer *mBuf)
576 {
577    U8               ret;
578    MsgLen           len;          /* number of actually sent octets */
579    CmInetNetAddr    peerAddr;     /* destination port address */
580    CmInetNetAddr    *dstAddr;
581    CmInetMemInfo    memInfo;                        
582    
583    memInfo.region = DU_APP_MEM_REGION;               
584    memInfo.pool   = DU_POOL;
585
586
587    if(sctpCfg.cuIpAddr.ipV4Pres)
588    {
589       peerAddr.type = CM_INET_IPV4ADDR_TYPE;
590       peerAddr.u.ipv4NetAddr = CM_INET_NTOH_U32(sctpCfg.cuIpAddr.ipV4Addr);
591       dstAddr = &peerAddr;
592    }
593    else
594    {
595       dstAddr = NULLP;
596    }
597
598    ret = cmInetSctpSendMsg(&sockFd, dstAddr, sctpCfg.cuPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
599    if(ret != ROK && ret != RWOULDBLOCK)
600    {
601       DU_LOG("\nSCTP : Failed sending the message");
602       RETVALUE(RFAILED);
603    }
604
605    RETVALUE(ROK);
606 } /* End of sctpSend */
607
608 /*******************************************************************
609  *
610  * @brief SCTP Assoc establishment request from DU
611  *
612  * @details
613  *
614  *    Function : sctpAssocReq
615  *
616  *    Functionality:
617  *          This function opens a socket at DU and
618  *          intiates SCTP connection.
619  *
620  * @params[in]
621  * @return ROK     - success
622  *         RFAILED - failure
623  *
624  * ****************************************************************/
625 void sctpAssocReq()
626 {
627    if(openSctpEndp() != ROK)
628    {
629       DU_LOG("\nSCTP : Failed while opening socket");
630    }
631    else if(bindSctpEndp() != ROK)
632    {
633       DU_LOG("\nSCTP : Failed while binding socket");
634    }
635    else if(sctpSetSockOpts() != ROK)
636    {
637       DU_LOG("\nSCTP : Failed while setting socket options");
638    }
639    else if(sctpConnect() != ROK)
640    {
641       DU_LOG("\nSCTP : Failed while connecting to peer");
642    }
643    else if(sctpSockPoll() != ROK)
644    {
645       DU_LOG("\nSCTP : Failed while polling");
646    }
647 } /* End of sctpAssocReq */
648
649 /**********************************************************************
650          End of file
651 **********************************************************************/