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