Stub changes for CU termination
[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                         exit(1);//Exit process on shutdown indication
355          break;
356       case CM_INET_SCTP_ADAPTATION_INDICATION :
357          DU_LOG("\nSCTP : Adaptation Indication received\n");
358          break;
359       case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
360          DU_LOG("\nSCTP : Partial Delivery Event received\n");
361          break;
362       default:
363          DU_LOG("\nSCTP : Invalid notification type\n");
364          break;
365    }
366
367    sctpNtfyInd(ntfy);
368    RETVALUE(ROK);
369 }/* End of sctpNtfyHdlr */
370
371 /*******************************************************************
372  *
373  * @brief Receives message on the socket
374  *
375  * @details
376  *
377  *    Function : sctpSockPoll
378  *
379  *    Functionality:
380  *      Receives message on the socket
381  *
382  * @params[in] 
383  * @return ROK     - success
384  *         RFAILED - failure
385  *
386  * ****************************************************************/
387 S16 sctpSockPoll()
388 {
389    U8   ret;
390    S16  numFds;
391    CmInetFdSet   readFd;
392    U16           port;
393    U32           timeout;           /* timeout for cmInetSelect() */
394    U32           *timeoutPtr;        /* pointer to timeout */
395    U32            flag;
396    Buffer        *mBuf;
397    Buffer        *egtpBuf;
398    MsgLen        bufLen;
399    MsgLen        egtpBufLen;
400    CmInetAddr    egtpFromAddr;   /* Egtp data sender address */
401    CmInetMemInfo memInfo;      /* buffer allocation info */
402    CmInetNetAddr addr;
403    CmInetSctpSndRcvInfo   info;
404    CmInetSctpNotification ntfy;
405
406    if (sockFd.blocking)
407    {
408       /* blocking */
409       timeoutPtr = NULLP;
410    }
411    else
412    {
413       /* non-blocking */
414       timeout = 0;
415       timeoutPtr = &timeout;
416    }
417    memInfo.region = CU_APP_MEM_REG;
418    memInfo.pool   = CU_POOL;
419    
420    egtpFromAddr.port = egtpCb.dstCb.dstPort;
421    egtpFromAddr.address = egtpCb.dstCb.dstIp;
422
423    CM_INET_FD_ZERO(&readFd);
424
425    while(1)
426    {
427       /* Receiving SCTP data */
428       CM_INET_FD_SET(&sockFd, &readFd);
429       ret = cmInetSelect(&readFd, NULLP, timeoutPtr, &numFds);
430       if (CM_INET_FD_ISSET(&sockFd, &readFd))
431       {
432          CM_INET_FD_CLR(&sockFd, &readFd);
433          ret = cmInetSctpRecvMsg(&sockFd, &addr, &port, &memInfo, &mBuf, &bufLen, &info, &flag, &ntfy);
434          if (ret != ROK)
435          {
436             DU_LOG("\nSCTP : Failed to receive sctp msg\n");
437          }
438          else
439          {
440             if ((flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0)
441             {
442                ret = sctpNtfyHdlr(&ntfy);
443                if(ret != ROK)
444                {
445                   DU_LOG("\nSCTP : Failed to process sctp notify msg\n");
446                }
447             }
448             else if(connUp) /* If data received */
449             {
450                F1APMsgHdlr(mBuf);
451                SPutMsg(mBuf);
452             }
453             else
454             {
455                SPutMsg(mBuf);
456             }
457          }
458       }
459
460       /* Receiving EGTP data */
461       egtpBufLen = -1;
462       ret = cmInetRecvMsg(&(egtpCb.recvTptSrvr.sockFd), &egtpFromAddr, &memInfo, &egtpBuf, &egtpBufLen, CM_INET_NO_FLAG);
463       if(ret == ROK && egtpBuf != NULLP)
464       {
465          DU_LOG("\nEGTP : Received message \n");
466          SPrntMsg(egtpBuf, 0 ,0);
467          cuEgtpHdlRecvMsg(egtpBuf);
468
469       }
470    };
471
472    RETVALUE(ROK);
473 }/* End of sctpSockPoll() */
474
475 /*******************************************************************
476  *
477  * @brief Send message on SCTP socket
478  *
479  * @details
480  *
481  *    Function : sctpSend 
482  *
483  *    Functionality:
484  *        Send message on SCTP socket
485  *
486  * @params[in] 
487  * @return ROK     - success
488  *         RFAILED - failure
489  *
490  * ****************************************************************/
491 S16 sctpSend(Buffer *mBuf)
492 {
493    U8               ret;
494    MsgLen           len;          /* number of actually sent octets */
495    CmInetNetAddr    peerAddr;     /* destination port address */
496    CmInetNetAddr    *dstAddr;
497    CmInetMemInfo    memInfo;                        
498    
499    memInfo.region = CU_APP_MEM_REG;               
500    memInfo.pool   = CU_POOL;
501
502
503    if(sctpCfg->duIpAddr.ipV4Pres)
504    {
505       peerAddr.type = CM_INET_IPV4ADDR_TYPE;
506       peerAddr.u.ipv4NetAddr = CM_INET_NTOH_U32(sctpCfg->duIpAddr.ipV4Addr);
507       dstAddr = &peerAddr;
508    }
509    else if(sctpCfg->duIpAddr.ipV6Pres)
510    {
511       peerAddr.type = CM_INET_IPV6ADDR_TYPE;
512       //CM_INET_COPY_IPV6ADDR(&(primDstAddr.u.ipv6NetAddr),&(sctpCfg->duIpAddr.ipV6Addr);
513       dstAddr = &peerAddr;
514    }
515    else
516    {
517       dstAddr = NULLP;
518    }
519
520    ret = cmInetSctpSendMsg(&sockFd, dstAddr, sctpCfg->duPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
521    if(ret != ROK && ret != RWOULDBLOCK)
522    {
523       DU_LOG("\nSCTP : Send message failed");
524       RETVALUE(RFAILED);
525    }
526
527    RETVALUE(ROK);
528 } /* End of sctpSend */
529
530 /*******************************************************************
531  *
532  * @brief Start SCTP at CU
533  *
534  * @details
535  *
536  *    Function : sctpStartReq
537  *
538  *    Functionality:
539  *         Start SCTP at CU
540  *
541  * @params[in]
542  * @return ROK     - success
543  *         RFAILED - failure
544  *
545  * ****************************************************************/
546 void sctpStartReq()
547 {
548    if(openSctpEndp() != ROK)
549    {
550       DU_LOG("\nSCTP : Failed while opening socket");
551    }
552    else if(bindSctpEndp() != ROK)
553    {
554       DU_LOG("\nSCTP : Failed while binding socket");
555    }
556    else if(sctpAccept() != ROK)
557    {
558       DU_LOG("\nSCTP : Failed while accepting connection");
559    }
560    else if(sctpSockPoll() != ROK)
561    {
562       DU_LOG("\nSCTP : Failed while polling");
563    }
564 } /* End of sctpAssocReq */
565
566 /**********************************************************************
567          End of file
568 **********************************************************************/