Release A code commit
[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 "f1ap_msg_hdl.h"
23 #include "cu_stub_sctp.h"
24
25 /* Global variable declaration */
26 CmInetFd   lstnSockFd; /* Listening Socket file descriptor */
27 CmInetFd   sockFd;     /* Socket File descriptor */
28 U8   socket_type;      /* Socket type */
29 Bool nonblocking;      /* Blocking/Non-blocking socket */
30 Bool connUp;           /* Is connection up */
31 int  assocId;          /* Assoc Id of connected assoc */
32
33 CmInetNetAddrLst localAddrLst;
34 CmInetNetAddrLst remoteAddrLst;
35
36 SctpParams *sctpCfg;            /* SCTP configurations at DU */
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    connUp = FALSE;
61    assocId = 0;
62    nonblocking = FALSE;
63    sctpCfg = &(cuCfgParams.sctpParams);
64    return ROK;
65
66 }
67
68 /**************************************************************************
69  * @brief Task Activation callback function. 
70  *
71  * @details
72  *
73  *      Function : sctpActvTsk 
74  * 
75  *      Functionality:
76  *           This function handles all SCTP messages received
77  *           This API is registered with SSI during the 
78  *           Task Registration of DU APP.
79  *     
80  * @param[in]  Pst     *pst, Post structure of the primitive.     
81  * @param[in]  Buffer *mBuf, Packed primitive parameters in the
82  *  buffer.
83  * @return ROK     - success
84  *         RFAILED - failure
85  *
86  ***************************************************************************/
87 S16 sctpActvTsk(Pst *pst, Buffer *mBuf)
88 {
89
90 //TODO: TBD
91    return ROK;
92 }
93
94 /*******************************************************************
95  *
96  * @brief Opens a non-blocking socket and binds to local address
97  *
98  * @details
99  *
100  *    Function : openSctpEndp
101  *
102  *    Functionality:
103  *         Opens a non-blocking socket and binds to local address
104  *
105  * @params[in] 
106  * @return ROK     - success
107  *         RFAILED - failure
108  *
109  * ****************************************************************/
110 S16 openSctpEndp()
111 {
112    U8 ret;
113    U8 numRetry = 0;
114
115    /* Opening a non-blocking SCTP socket */
116    socket_type = CM_INET_STREAM;
117
118    do{
119       ret = cmInetSocket(socket_type, &lstnSockFd, IPPROTO_SCTP,(sctpCfg->cuIpAddr.ipV4Pres ? AF_INET : AF_INET6));
120       if (ret != ROK)
121       {
122          numRetry++;
123          if(numRetry >= MAX_RETRY)
124          {
125             printf("\nAll attempts to open socket failed.");
126             /* Send indication to du_app */
127             RETVALUE(RFAILED);
128          }
129          else
130          {
131             printf("\nRetrying socket opening"); 
132          }
133       }
134       else
135       {
136          printf("\nSocket[%d] opened successfully",lstnSockFd.fd);
137          break;
138       }
139    }while(numRetry < MAX_RETRY);
140
141    RETVALUE(ROK);
142 } /* End of openSctpEndp */
143
144
145 /*******************************************************************
146  *
147  * @brief Bind socket to local Ip address and port
148  *
149  * @details
150  *
151  *    Function : bindSctpEndp
152  *
153  *    Functionality:
154  *      -Bind socket to local Ip address and port
155  *
156  * @params[in] 
157  * @return ROK     - success
158  *         RFAILED - failure
159  *
160  * ****************************************************************/
161 S16 bindSctpEndp()
162 {
163
164    U8 ret;
165    U8 numRetry = 0;
166
167    /* Binding the socket with local address */
168    localAddrLst.count = 1;
169    if(sctpCfg->cuIpAddr.ipV4Pres)
170    {
171       localAddrLst.addrs[0].type = CM_INET_IPV4ADDR_TYPE;
172       localAddrLst.addrs[0].u.ipv4NetAddr = CM_INET_NTOH_U32(sctpCfg->cuIpAddr.ipV4Addr);
173    }
174    else if(sctpCfg->cuIpAddr.ipV6Pres)
175    {
176       localAddrLst.addrs[0].type = CM_INET_IPV6ADDR_TYPE;
177      // CM_INET_COPY_IPV6ADDR(&(localAddrLst.addrs[0].u.ipv6NetAddr),&(sctpCfg->cuIpAddr.ipV6Addr);         
178    }
179    else
180    {
181       localAddrLst.addrs[0].type = CM_INET_IPV4ADDR_TYPE;
182       localAddrLst.addrs[0].u.ipv4NetAddr = 0;
183    } 
184
185    do{
186       ret = cmInetSctpBindx(&lstnSockFd, &localAddrLst, sctpCfg->cuPort);
187       if (ret != ROK)
188       {
189          numRetry++;
190          if(numRetry >= MAX_RETRY)
191          {
192             printf("\nAll attempts to bind socket failed.");
193             cmInetClose(&lstnSockFd);
194             /* Send indication to du_app */
195             RETVALUE(RFAILED);
196          }
197          else
198          {
199             printf("\nRetrying socket binding");
200          }
201       }
202       else
203       {
204          printf("\nSocket bind successful");
205          break;
206       }
207    }while(numRetry < MAX_RETRY);
208
209   RETVALUE(ROK);
210
211 } /* End of bindSctpEndp() */
212
213 /*******************************************************************
214  *
215  * @brief Sets socket options as per requirement
216  *
217  * @details
218  *
219  *    Function : sctpSetSockOpts
220  *
221  *    Functionality: 
222  *       Sets socket options as per requirement
223  *
224  * @params[in] 
225  * @return ROK     - success
226  *         RFAILED - failure
227  *
228  * ****************************************************************/
229 S16 sctpSetSockOpts()
230 {
231    CmSctpEvent sctpEvent;
232   
233    sctpEvent.dataIoEvent          = TRUE;
234    sctpEvent.associationEvent     = TRUE;
235    sctpEvent.addressEvent         = TRUE;
236    sctpEvent.sendFailureEvent     = TRUE;
237    sctpEvent.peerErrorEvent       = TRUE;
238    sctpEvent.shutdownEvent        = TRUE;
239    sctpEvent.partialDeliveryEvent = TRUE;
240    sctpEvent.adaptationLayerEvent = TRUE;
241
242    cmInetSetOpt(&sockFd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent);
243    RETVALUE(ROK);
244 }
245
246 /*******************************************************************
247  *
248  * @brief Initiates connection with peer SCTP
249  *
250  * @details
251  *
252  *    Function : sctpAccept
253  *
254  *    Functionality:
255  *       Establishes SCTP connection with peer.
256  *       Here, DU-SCTP will initate connection towards CU-SCTP
257  *
258  * @params[in] 
259  * @return ROK     - success
260  *         RFAILED - failure
261  *
262  * ****************************************************************/
263 S16 sctpAccept()
264 {
265    U8  ret;
266    CmInetAddr    peerAddr;
267
268    ret = cmInetListen(&lstnSockFd, 1);;
269    if (ret != ROK)
270    {
271       printf("\nListening on socket failed");
272       cmInetClose(&lstnSockFd);
273       RETVALUE(RFAILED);
274    }
275
276    while(!connUp)
277    {
278       ret = cmInetAccept(&lstnSockFd, &peerAddr, &sockFd);
279       if (ret == ROKDNA)
280       {
281          continue;
282       }
283       else if(ret != ROK)
284       {
285          printf("\nFailed to accept connection");
286          RETVALUE(RFAILED);
287       }
288       else
289       {
290          connUp = TRUE;
291          sctpSetSockOpts();
292          printf("\nAccepted incoming connection");
293          break;
294       }
295    }
296
297    RETVALUE(ROK);
298 }/* End of sctpAccept() */
299
300 /*******************************************************************
301  *
302  * @brief Handles an SCTP notification message
303  *
304  * @details
305  *
306  *    Function : sctpNtfyHdlr
307  *
308  *    Functionality:
309  *      Handles an SCTP notification message
310  *
311  * @params[in] Notify message
312  *
313  * @return ROK     - success
314  *         RFAILED - failure
315  *
316  * ****************************************************************/
317 S16 sctpNtfyHdlr(CmInetSctpNotification *ntfy)
318 {
319    switch(ntfy->header.nType)
320    {
321       case CM_INET_SCTP_ASSOC_CHANGE :
322          switch(ntfy->u.assocChange.state)
323          {
324             case CM_INET_SCTP_COMM_UP:
325                printf("\nSCTP notify assocchange(comm up) received");
326                connUp = TRUE;
327                break;
328             case CM_INET_SCTP_COMM_LOST:
329                printf("\nSCTP notify assocchange(comm lost) received");
330                connUp = FALSE;
331                break;
332             case CM_INET_SCTP_RESTART:
333                printf("\nSCTP notify assocchange(sctp restart) received");
334                connUp = FALSE;
335                break;
336             case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */
337                printf("\nSCTP notify assocchange(shutdown complete) received\n");
338                connUp = FALSE;
339                break;
340             case CM_INET_SCTP_CANT_STR_ASSOC:
341                printf("\nSCTP notify assocchange(cant str assoc) received\n");
342                connUp = FALSE;
343                break;
344             default:
345                printf("\nInvalid event");
346                break;
347          }
348          break;
349       case CM_INET_SCTP_PEER_ADDR_CHANGE :
350          printf("\nSCTP notify peer addr change received");
351          /* Need to add handler */
352          break;
353       case CM_INET_SCTP_REMOTE_ERROR :
354          printf("\nSCTP notify remote error received");
355          break;
356       case CM_INET_SCTP_SEND_FAILED :
357          printf("\nSCTP notify send failed received\n");
358          break;
359       case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */
360          printf("\nSCTP notify shutdown event received\n");
361          connUp = FALSE;
362          break;
363       case CM_INET_SCTP_ADAPTATION_INDICATION :
364          printf("\nSCTP notify adaptation indication received\n");
365          break;
366       case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
367          printf("\nSCTP notify partial delivery received\n");
368          break;
369       default:
370          printf("\nInvalid sctp notification type\n");
371          break;
372    }
373
374    sctpNtfyInd(ntfy);
375    RETVALUE(ROK);
376 }/* End of sctpNtfyHdlr */
377
378 /*******************************************************************
379  *
380  * @brief Receives message on the socket
381  *
382  * @details
383  *
384  *    Function : sctpSockPoll
385  *
386  *    Functionality:
387  *      Receives message on the socket
388  *
389  * @params[in] 
390  * @return ROK     - success
391  *         RFAILED - failure
392  *
393  * ****************************************************************/
394 S16 sctpSockPoll()
395 {
396    U8   ret;
397    S16  numFds;
398    CmInetFdSet   readFd;
399    U16           port;
400    U32           timeout;           /* timeout for cmInetSelect() */
401    U32           *timeoutPtr;        /* pointer to timeout */
402    U32            flag;
403    Buffer        *mBuf;
404    MsgLen        bufLen;
405    CmInetMemInfo memInfo;      /* buffer allocation info */
406    CmInetNetAddr addr;
407    CmInetSctpSndRcvInfo   info;
408    CmInetSctpNotification ntfy;
409
410    if (sockFd.blocking)
411    {
412       /* blocking */
413       timeoutPtr = NULLP;
414    }
415    else
416    {
417       /* non-blocking */
418       timeout = 0;
419       timeoutPtr = &timeout;
420    }
421    memInfo.region = CU_APP_MEM_REG;
422    memInfo.pool   = CU_POOL;
423    CM_INET_FD_ZERO(&readFd);
424
425    while(1)
426    {
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             printf("\nFailed 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                   printf("\nFailed to process sctp notify msg\n");
445                }
446             }
447             else if(connUp) /* If data received */
448             {
449                F1InmsgHdlr(mBuf);
450                SPutMsg(mBuf);
451             }
452             else
453             {
454                SPutMsg(mBuf);
455             }
456          }
457       }
458    };
459
460    RETVALUE(ROK);
461 }/* End of sctpSockPoll() */
462
463 /*******************************************************************
464  *
465  * @brief Send message on SCTP socket
466  *
467  * @details
468  *
469  *    Function : sctpOutMsgSend 
470  *
471  *    Functionality:
472  *        Send message on SCTP socket
473  *
474  * @params[in] 
475  * @return ROK     - success
476  *         RFAILED - failure
477  *
478  * ****************************************************************/
479 S16 sctpOutMsgSend(Buffer *mBuf)
480 {
481    U8               ret;
482    MsgLen           len;          /* number of actually sent octets */
483    CmInetNetAddr    peerAddr;     /* destination port address */
484    CmInetNetAddr    *dstAddr;
485    CmInetMemInfo    memInfo;                        
486    
487    memInfo.region = CU_APP_MEM_REG;               
488    memInfo.pool   = CU_POOL;
489
490
491    if(sctpCfg->duIpAddr.ipV4Pres)
492    {
493       peerAddr.type = CM_INET_IPV4ADDR_TYPE;
494       peerAddr.u.ipv4NetAddr = CM_INET_NTOH_U32(sctpCfg->duIpAddr.ipV4Addr);
495       dstAddr = &peerAddr;
496    }
497    else if(sctpCfg->duIpAddr.ipV6Pres)
498    {
499       peerAddr.type = CM_INET_IPV6ADDR_TYPE;
500       //CM_INET_COPY_IPV6ADDR(&(primDstAddr.u.ipv6NetAddr),&(sctpCfg->duIpAddr.ipV6Addr);
501       dstAddr = &peerAddr;
502    }
503    else
504    {
505       dstAddr = NULLP;
506    }
507
508    ret = cmInetSctpSendMsg(&sockFd, dstAddr, sctpCfg->duPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
509    if(ret != ROK && ret != RWOULDBLOCK)
510    {
511       printf("\nFailed sending the message");
512       RETVALUE(RFAILED);
513    }
514
515    RETVALUE(ROK);
516 } /* End of sctpOutMsgSend */
517
518 /*******************************************************************
519  *
520  * @brief Start SCTP at CU
521  *
522  * @details
523  *
524  *    Function : sctpStartReq
525  *
526  *    Functionality:
527  *         Start SCTP at CU
528  *
529  * @params[in]
530  * @return ROK     - success
531  *         RFAILED - failure
532  *
533  * ****************************************************************/
534 void sctpStartReq()
535 {
536    if(openSctpEndp() != ROK)
537    {
538       printf("\nFailed while opening socket");
539    }
540    else if(bindSctpEndp() != ROK)
541    {
542       printf("\nFailed while binding socket");
543    }
544    else if(sctpAccept() != ROK)
545    {
546       printf("\nFailed while accepting connection");
547    }
548    else if(sctpSockPoll() != ROK)
549    {
550       printf("\nFailed while polling");
551    }
552 } /* End of sctpAssocReq */
553
554 /**********************************************************************
555          End of file
556 **********************************************************************/