39874f69ed81437effdeb6026abdb447fe55456c
[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 "common_def.h" 
22 #include "cu_f1ap_msg_hdl.h"
23 #include "cu_stub_sctp.h"
24 #include "cu_stub_egtp.h"
25 #include "du_log.h"
26
27 CuSctpDestCb f1Params;
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()
49 {
50    DU_LOG("\n\nDEBUG  -->  SCTP : Initializing");
51    connUp = FALSE;
52    assocId = 0;
53    nonblocking = FALSE;
54    sctpCfg = cuCfgParams.sctpParams;
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
81 //TODO: TBD
82    return ROK;
83 }
84
85 /**************************************************************************
86  * @brief Function to configure the Sctp Params during config Request
87  *
88  * @details
89  *
90  *      Function : duSctpCfgReq
91  * 
92  *      Functionality:
93  *           This function configures SCTP Params during the config Request
94  *     
95  * @return ROK     - success
96  *         RFAILED - failure
97  *
98  ***************************************************************************/
99
100 S16 sctpCfgReq()
101 {
102
103 /* Fill F1 Params */
104    f1Params.destPort             = sctpCfg.duPort;
105    f1Params.srcPort              = sctpCfg.cuPort;
106    f1Params.bReadFdSet           = ROK;
107    memset(&f1Params.sockFd, -1, sizeof(CmInetFd));
108    memset(&f1Params.lstnSockFd, -1, sizeof(CmInetFd));
109    fillDestNetAddr(&f1Params.destIpNetAddr, &sctpCfg.duIpAddr);
110
111    return ROK;
112 }
113
114
115 /*******************************************************************
116  *
117  * @brief Fills the address List of the source Ip Address
118  *
119  * @details
120  *
121  *    Function : fillAddrLst
122  *
123  *    Functionality:
124  *       Fills the address List of source Ip Address
125  *
126  * @params[in] CmInetNetAddrLst *addrLstPtr, Address List pointer
127  * @params[in] F1IpAddr *srcIpAddr, src Ip Adrress to be filled in the Address List
128  * @return ROK     - success
129  *         RFAILED - failure
130  *
131  ******************************************************************/
132
133 S16 fillAddrLst(CmInetNetAddrLst *addrLstPtr, SctpIpAddr *ipAddr)
134
135    addrLstPtr->count++;
136    addrLstPtr->addrs[(addrLstPtr->count - 1)].type = CM_INET_IPV4ADDR_TYPE;
137    addrLstPtr->addrs[(addrLstPtr->count - 1)].u.ipv4NetAddr = CM_INET_NTOH_UINT32(ipAddr->ipV4Addr);
138
139    return ROK;
140 }
141
142 /******************************************************************************
143  *
144  * @brief Fills the address List of the source Ip Address
145  *
146  * @details
147  *
148  *    Function : fillDestNetAddr
149  *
150  *    Functionality:
151  *       Fills the address List of destinatoion Ip Address
152  *
153  * @params[in] CmInetNetAddr *destAddrPtr, Address List pointer
154  * @params[in] F1IpAddr *dstIpAddr, destIp Address to be filled in the Address List
155  * @return ROK     - success
156  *         RFAILED - failure
157  *
158  *******************************************************************************/
159 S16 fillDestNetAddr(CmInetNetAddr *destAddrPtr, SctpIpAddr *dstIpPtr)
160 {
161    /* Filling destination address */
162    destAddrPtr->type = CM_INET_IPV4ADDR_TYPE;
163    destAddrPtr->u.ipv4NetAddr = CM_INET_NTOH_UINT32(dstIpPtr->ipV4Addr);
164    return ROK;
165 }
166
167 /******************************************************************************
168  *
169  * @brief Eastablishes the Assoc Req for the received interface type
170  *
171  * @details
172  *
173  *    Function : sctpStartReq
174  *
175  *    Functionality:
176  *       Eastablishes the Assoc Req for the received interface type
177  *
178  * @params[in] DuSctpDestCb *paramPtr
179  * @return ROK     - success
180  *         RFAILED - failure
181  *
182  *******************************************************************************/
183
184 S16 sctpStartReq()
185 {
186    S16 ret = ROK;
187    socket_type = CM_INET_STREAM;
188    fillAddrLst(&f1Params.localAddrLst, &sctpCfg.cuIpAddr);
189
190    if((ret = cmInetSocket(socket_type, &f1Params.lstnSockFd, IPPROTO_SCTP) != ROK))
191    {
192       DU_LOG("\nERROR  -->  SCTP : Socket[%d] coudnt open for listening", f1Params.lstnSockFd.fd);
193    } 
194    else if((ret = cmInetSctpBindx(&f1Params.lstnSockFd, &f1Params.localAddrLst, f1Params.srcPort)) != ROK)
195    {
196       DU_LOG("\nERROR  -->  SCTP: Binding failed at CU");
197    }
198    else if((ret = sctpAccept(&f1Params.lstnSockFd, &f1Params.peerAddr, &f1Params.sockFd)) != ROK)
199    {
200       DU_LOG("\nERROR  -->  SCTP: Unable to accept the connection at CU");
201    }
202    else if(sctpSockPoll() != ROK)
203    {
204       DU_LOG("\nERROR  -->  SCTP: Polling failed to start at CU");
205    }
206    return (ret);
207 }
208 /*******************************************************************
209  *
210  * @brief Sets socket options as per requirement
211  *
212  * @details
213  *
214  *    Function : sctpSetSockOpts
215  *
216  *    Functionality: 
217  *       Sets socket options as per requirement
218  *
219  * @params[in] 
220  * @return ROK     - success
221  *         RFAILED - failure
222  *
223  * ****************************************************************/
224 S16 sctpSetSockOpts(CmInetFd *sock_Fd)
225 {
226    S16 ret = ROK;
227    CmSctpEvent sctpEvent;
228   
229    sctpEvent.dataIoEvent          = TRUE;
230    sctpEvent.associationEvent     = TRUE;
231    sctpEvent.addressEvent         = TRUE;
232    sctpEvent.sendFailureEvent     = TRUE;
233    sctpEvent.peerErrorEvent       = TRUE;
234    sctpEvent.shutdownEvent        = TRUE;
235    sctpEvent.partialDeliveryEvent = TRUE;
236    sctpEvent.adaptationLayerEvent = TRUE;
237
238    if((ret = cmInetSetOpt(sock_Fd, CM_SOCKOPT_LEVEL_SCTP, CM_SOCKOPT_OPT_SCTP_EVENTS, &sctpEvent)) != ROK)
239    {
240      ret = RFAILED;
241    }
242   
243    return (ret);
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(CmInetFd *lstnSock_Fd, CmInetAddr *peerAddr, CmInetFd *sock_Fd)
264 {
265    uint8_t  ret;
266
267    ret = cmInetListen(lstnSock_Fd, 1);
268    if (ret != ROK)
269    {
270       DU_LOG("\nERROR  -->  SCTP : Listening on socket failed");
271       cmInetClose(lstnSock_Fd);
272       return RFAILED;
273    }
274    
275    DU_LOG("\nINFO  -->  SCTP : Connecting");
276
277    while(!connUp)
278    {
279       ret = cmInetAccept(lstnSock_Fd, peerAddr, sock_Fd);
280       if (ret == ROKDNA)
281       {
282          continue;
283       }
284       else if(ret != ROK)
285       {
286          DU_LOG("\nERROR  -->  SCTP : Failed to accept connection");
287          return RFAILED;
288       }
289       else
290       {
291          connUp = TRUE;
292          sctpSetSockOpts(sock_Fd);
293          break;
294       }
295    }
296    DU_LOG("\nINFO  -->  SCTP : Connection established");
297
298    return ROK;
299 }
300
301 /*******************************************************************
302  *
303  * @brief Handles an SCTP notification message
304  *
305  * @details
306  *
307  *    Function : sctpNtfyHdlr
308  *
309  *    Functionality:
310  *      Handles an SCTP notification message
311  *
312  * @params[in] Notify message
313  *
314  * @return ROK     - success
315  *         RFAILED - failure
316  *
317  * ****************************************************************/
318 S16 sctpNtfyHdlr(CmInetSctpNotification *ntfy)
319 {
320    switch(ntfy->header.nType)
321    {
322       case CM_INET_SCTP_ASSOC_CHANGE :
323          DU_LOG("\nINFO  -->  SCTP : Assoc change notification received");
324          switch(ntfy->u.assocChange.state)
325          {
326             case CM_INET_SCTP_COMM_UP:
327                DU_LOG("DEBUG  -->  Event : COMMUNICATION UP");
328                connUp = TRUE;
329                break;
330             case CM_INET_SCTP_COMM_LOST:
331                DU_LOG("DEBUG  -->  Event : COMMUNICATION LOST");
332                connUp = FALSE;
333                break;
334             case CM_INET_SCTP_RESTART:
335                DU_LOG("DEBUG  -->  Event : SCTP RESTART");
336                connUp = FALSE;
337                break;
338             case CM_INET_SCTP_SHUTDOWN_COMP: /* association gracefully shutdown */
339                DU_LOG("DEBUG  -->  Event : SHUTDOWN COMPLETE");
340                connUp = FALSE;
341                break;
342             case CM_INET_SCTP_CANT_STR_ASSOC:
343                DU_LOG("DEBUG  -->  Event : CANT START ASSOC");
344                connUp = FALSE;
345                break;
346             default:
347                DU_LOG("\nERROR  -->  Invalid event");
348                break;
349          }
350          break;
351       case CM_INET_SCTP_PEER_ADDR_CHANGE :
352          DU_LOG("\nINFO  -->  SCTP : Peer Address Change notificarion received");
353          /* Need to add handler */
354          break;
355       case CM_INET_SCTP_REMOTE_ERROR :
356          DU_LOG("\nINFO  -->  SCTP : Remote Error notification received");
357          break;
358       case CM_INET_SCTP_SEND_FAILED :
359          DU_LOG("\nINFO  -->  SCTP : Send Failed notification received\n");
360          break;
361       case CM_INET_SCTP_SHUTDOWN_EVENT : /* peer socket gracefully closed */
362          DU_LOG("\nINFO  -->  SCTP : Shutdown Event notification received\n");
363          connUp = FALSE;
364          exit(0);
365          break;
366       case CM_INET_SCTP_ADAPTATION_INDICATION :
367          DU_LOG("\nINFO  -->  SCTP : Adaptation Indication received\n");
368          break;
369       case CM_INET_SCTP_PARTIAL_DELIVERY_EVENT:
370          DU_LOG("\nINFO  -->  SCTP : Partial Delivery Event received\n");
371          break;
372       default:
373          DU_LOG("\nERROR  -->  SCTP : Invalid notification type\n");
374          break;
375    }
376
377    sctpNtfyInd(ntfy);
378    return ROK;
379 }/* End of sctpNtfyHdlr */
380
381 /*******************************************************************
382  *
383  * @brief Receives message on the socket
384  *
385  * @details
386  *
387  *    Function : sctpSockPoll
388  *
389  *    Functionality:
390  *      Receives message on the socket
391  *
392  * @params[in] 
393  * @return ROK     - success
394  *         RFAILED - failure
395  *
396  * ****************************************************************/
397 S16 sctpSockPoll()
398 {
399    uint16_t      ret = ROK;
400    uint32_t      timeout;
401    uint32_t      *timeoutPtr;
402    Buffer        *egtpBuf;
403    MsgLen        egtpBufLen;
404    CmInetAddr    egtpFromAddr;
405    CmInetMemInfo memInfo;
406    sctpSockPollParams f1PollParams;
407
408    memset(&f1PollParams, 0, sizeof(sctpSockPollParams));
409     
410    egtpFromAddr.port = egtpCb.dstCb.dstPort;
411    egtpFromAddr.address = egtpCb.dstCb.dstIp;
412
413    if(f1Params.sockFd.blocking)
414    {
415       /* blocking */
416       timeoutPtr = NULLP;
417    }
418    else
419    {
420       /* non-blocking */
421       timeout = 0;
422       timeoutPtr = &timeout;
423    }
424    memInfo.region = CU_APP_MEM_REG;
425    memInfo.pool   = CU_POOL;
426    
427    CM_INET_FD_ZERO(&f1PollParams.readFd);
428
429    while(1)
430    {
431       if((ret = processPolling(&f1PollParams, &f1Params.sockFd, timeoutPtr, &memInfo)) != ROK)
432       {
433          DU_LOG("\nERROR  -->  SCTP : Failed to RecvMsg for F1 at CU\n");
434       }
435
436       /* Receiving EGTP data */
437       egtpBufLen = -1;
438       ret = cmInetRecvMsg(&(egtpCb.recvTptSrvr.sockFd), &egtpFromAddr, &memInfo, &egtpBuf, &egtpBufLen, CM_INET_NO_FLAG);
439       if(ret == ROK && egtpBuf != NULLP)
440       {
441          DU_LOG("\nINFO  -->  EGTP : Received message \n");
442          ODU_PRINT_MSG(egtpBuf, 0 ,0);
443          cuEgtpHdlRecvMsg(egtpBuf);
444
445       }
446    };
447    return (ret);
448 }/* End of sctpSockPoll() */
449
450 /*******************************************************************
451  *
452  * @brief checks for valid readFd and process the InetSctpRecvMsg
453  * during polling 
454  *
455  * @details
456  *
457  *    Function : processPolling
458  *
459  *    Functionality:
460  *         checks for valid readFd and process the InetSctpRecvMsg
461  *         during polling
462  *
463  * @params[in]  Params required for polling
464  * @params[in]  SockFd for file descriptor
465  * @params[in]  timeoutPtr indicates the timeout value
466  * @params[in]  MemInfo indicates memory region
467  *
468  * @return ROK     - success
469  *         RFAILED - failure
470  *
471  * ****************************************************************/
472
473 S16 processPolling(sctpSockPollParams *pollParams, CmInetFd *sockFd, uint32_t *timeoutPtr, CmInetMemInfo *memInfo)
474 {
475    uint16_t ret = ROK;
476    CM_INET_FD_SET(sockFd, &pollParams->readFd);
477    ret = cmInetSelect(&pollParams->readFd, NULLP, timeoutPtr, &pollParams->numFd);
478    if(CM_INET_FD_ISSET(sockFd, &pollParams->readFd))
479    {
480       CM_INET_FD_CLR(sockFd, &pollParams->readFd);
481       ret = cmInetSctpRecvMsg(sockFd, &pollParams->addr, &pollParams->port, memInfo, &pollParams->mBuf, &pollParams->bufLen, &pollParams->info, &pollParams->flag, &pollParams->ntfy);
482       if(connUp & (ret != ROK))
483       {
484          f1Params.bReadFdSet = RFAILED;
485       }
486       else
487       {
488          if(((pollParams->flag & CM_INET_SCTP_MSG_NOTIFICATION) != 0) && (ret == ROK))
489          {
490             ret = sctpNtfyHdlr(&pollParams->ntfy);
491             if(ret != ROK)
492             {
493                DU_LOG("\nERROR  -->  SCTP : Failed to process sctp notify msg\n");
494             }
495          }
496          else if(connUp & (pollParams->port == f1Params.destPort))
497          {  
498             F1APMsgHdlr(pollParams->mBuf);
499             ODU_PUT_MSG_BUF(pollParams->mBuf);
500          }
501          else
502          {
503             ODU_PUT_MSG_BUF(pollParams->mBuf);
504          }
505       } 
506   }
507   return ROK;
508 }/* End of sctpSockPoll() */
509
510 /*******************************************************************
511  *
512  * @brief Send message on SCTP socket
513  *
514  * @details
515  *
516  *    Function : sctpSend 
517  *
518  *    Functionality:
519  *        Send message on SCTP socket
520  *
521  * @params[in] 
522  * @return ROK     - success
523  *         RFAILED - failure
524  *
525  * ****************************************************************/
526 S16 sctpSend(Buffer *mBuf)
527 {
528    uint8_t          ret = ROK;
529    MsgLen           len = 0;          /* number of actually sent octets */
530    CmInetMemInfo    memInfo;                        
531   
532    memset(&memInfo , 0, sizeof(CmInetMemInfo));
533    memInfo.region = CU_APP_MEM_REG;               
534    memInfo.pool   = CU_POOL;
535
536    ret = cmInetSctpSendMsg(&f1Params.sockFd, &f1Params.destIpNetAddr, f1Params.destPort, &memInfo, mBuf, &len, 0, FALSE, 0, 0/*SCT_PROTID_NONE*/, RWOULDBLOCK);
537
538    if(ret != ROK && ret != RWOULDBLOCK)
539    {
540       DU_LOG("\nERROR  -->  SCTP : Send message failed");
541       return RFAILED;
542    }
543
544    return ROK;
545 } /* End of sctpSend */
546
547 /**********************************************************************
548          End of file
549 **********************************************************************/