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