Added code for MAC-PHY interface, DU_APP, F1AP, SCTP and CU stub
[o-du/l2.git] / src / cu_app / cu_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 <fcntl.h>
22 #include <netdb.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <errno.h>  
26 #include <unistd.h>
27
28 #include "cu_sctp.h"
29
30 /* Global variable declaration */
31 S8   sockFd;
32 S8   lstnSockFd;
33 U8   socket_type;
34 Bool nonblocking;
35 Bool connUp;
36 int  assocId;
37
38 sockaddr_storage_t local_addr;
39 sockaddr_storage_t remote_addr;
40 U8   la_len;
41 U8   ra_len;
42
43 SctpParams *sctpCfg;
44
45 /**************************************************************************
46  * @brief Task Initiation callback function. 
47  *
48  * @details
49  *
50  *     Function : sctpActvInit 
51  *    
52  *     Functionality:
53  *             This function is supplied as one of parameters during SCTP's 
54  *             task registration. SSI will invoke this function once, after
55  *             it creates and attaches this TAPA Task to a system task.
56  *     
57  * @param[in]  Ent entity, the entity ID of this task.     
58  * @param[in]  Inst inst, the instance ID of this task.
59  * @param[in]  Region region, the region ID registered for memory 
60  *              usage of this task.
61  * @param[in]  Reason reason.
62  * @return ROK     - success
63  *         RFAILED - failure
64  ***************************************************************************/
65 S16 sctpActvInit(Ent entity, Inst inst, Region region, Reason reason)
66 {
67    sockFd = 0;
68    lstnSockFd = 0;
69    connUp = FALSE;
70    assocId = 0;
71    nonblocking = FALSE;
72    sctpCfg = &(cuCfgParams.sctpParams);
73    return ROK;
74
75 }
76
77 /**************************************************************************
78  * @brief Task Activation callback function. 
79  *
80  * @details
81  *
82  *      Function : sctpActvTsk 
83  * 
84  *      Functionality:
85  *           This function handles all SCTP messages received
86  *           This API is registered with SSI during the 
87  *           Task Registration of DU APP.
88  *     
89  * @param[in]  Pst     *pst, Post structure of the primitive.     
90  * @param[in]  Buffer *mBuf, Packed primitive parameters in the
91  *  buffer.
92  * @return ROK     - success
93  *         RFAILED - failure
94  *
95  ***************************************************************************/
96 S16 sctpActvTsk(Pst *pst, Buffer *mBuf)
97 {
98
99 //TODO: TBD
100    return ROK;
101 }
102
103 /*******************************************************************
104  *
105  * @brief Converts internet address to sockaddr type
106  *
107  * @details
108  *
109  *    Function : getSockAddr 
110  *
111  *    Functionality:
112  *        Converts internet address to sockaddr type
113  *
114  * @params[in] 
115  * @return ROK     - success
116  *         RFAILED - failure
117  *
118  * ****************************************************************/
119
120 S16 getSockAddr(char *hostIp, U16 portNum, Bool ipv4Pres, Bool local)
121 {
122    sockaddr_storage_t address;
123    struct hostent *host;
124    void *la_raw;
125    U8    addr_len;
126
127    /* Getting the transport address for local host name */
128    if(ipv4Pres)
129    {
130       host = gethostbyname(hostIp);
131       if (host == NULL || host->h_length < 1)
132       {
133          printf("\nBad hostname: %s", hostIp);
134          RETVALUE(NULLP);
135       }
136       addr_len = sizeof(address.v4);
137       la_raw = &address.v4.sin_addr;
138       address.v4.sin_family = AF_INET;
139       address.v4.sin_port = htons(portNum);
140    }
141    else
142    {
143       host = gethostbyname2(hostIp, AF_INET6);
144       if (host == NULL || host->h_length < 1)
145       {
146          printf("\n Bad hostname: %s", hostIp);
147          RETVALUE(RFAILED);
148       }
149       addr_len = sizeof(address.v6);
150       la_raw = &address.v6.sin6_addr;
151       address.v6.sin6_family = AF_INET6;
152       address.v6.sin6_port = htons(portNum);
153       address.v6.sin6_scope_id = 0;
154    }
155
156    memcpy((U8 *)la_raw, (U8 *)host->h_addr_list[0], host->h_length);
157    
158    if(local)
159    {
160       local_addr = address;
161       la_len = addr_len;
162    }
163    else
164    {
165       remote_addr = address;
166       ra_len = addr_len;
167    }
168
169    RETVALUE(ROK);
170 } /* End of getSockAddr() */
171
172 /*******************************************************************
173  *
174  * @brief Opens a non-blocking socket and binds to local address
175  *
176  * @details
177  *
178  *    Function : openSctpEndp
179  *
180  *    Functionality:
181  *         Opens a non-blocking socket and binds to local address
182  *
183  * @params[in] 
184  * @return ROK     - success
185  *         RFAILED - failure
186  *
187  * ****************************************************************/
188 S16 openSctpEndp()
189 {
190   sa_family_t la_family;
191   U8   la_len;
192   U8   error;
193
194   printf("\nEntering openSctpEndp");
195
196   /* Getting the transport address for local host name */
197   if(sctpCfg->cuIpAddr.ipV4Pres)
198   {
199      printf("\nLocal Host Address %s",cuCfgParams.sctpParams.cuIpAddr.ipV4Addr);
200      if(getSockAddr(sctpCfg->cuIpAddr.ipV4Addr, sctpCfg->cuPort, TRUE, TRUE) != ROK )
201      {
202         printf("\nUnable to get local address");
203         RETVALUE(RFAILED);
204      }
205      la_len = sizeof(local_addr.v4);
206      la_family = AF_INET;
207   }
208   else
209   {
210      if(getSockAddr(sctpCfg->cuIpAddr.ipV6Addr, sctpCfg->cuPort, FALSE, TRUE) != ROK )
211      {
212         printf("\nUnable to get local address");
213         RETVALUE(RFAILED);
214      }
215      la_len = sizeof(local_addr.v6);
216      la_family = AF_INET6;
217   }
218
219   socket_type = SOCK_STREAM;
220   
221   /* Creating new end point */
222   lstnSockFd = socket(la_family, socket_type, IPPROTO_SCTP);  
223   if (lstnSockFd < 0) 
224   {
225      printf("\n Failed to create socket  %s", strerror(errno));
226      RETVALUE(RFAILED);
227   }
228
229   /* Binding socket to local address and port */
230   error = bind(lstnSockFd, &local_addr.sa, la_len); 
231   if(error != 0)
232   {
233      printf("\n Failed to bind to socket. Error [%s]", strerror(errno));
234      RETVALUE(RFAILED);
235   }
236
237   /* Setting socket as non-blocking*/
238   error = fcntl(lstnSockFd, F_SETFL, O_NONBLOCK);
239   if (error != 0) 
240   {
241      printf("\n Failed to set socket as non blocking. Error [%s]", strerror(errno));
242      RETVALUE(RFAILED);
243   }
244   else
245   {
246      nonblocking = TRUE;
247   }
248
249   RETVALUE(ROK);
250
251 } /* End of openSctpEndp() */
252
253 /*******************************************************************
254  *
255  * @brief Listens for connection request from peer SCTP
256  *
257  * @details
258  *
259  *    Function : sctpConnAccept
260  *
261  *    Functionality:
262  *       Listens and accepts SCTP connection request from peer.
263  *       Here, DU-SCTP will initate connection towards CU-SCTP
264  *
265  * @params[in] 
266  * @return ROK     - success
267  *         RFAILED - failure
268  *
269  * ****************************************************************/
270 S16 sctpConnAccept()
271 {
272    U8  error;
273    U8  ret;
274    socklen_t len = 0;
275
276    /* Getting the transport address for remote host name */
277    if(sctpCfg->duIpAddr.ipV4Pres)
278    {
279       ret = getSockAddr(sctpCfg->duIpAddr.ipV4Addr, sctpCfg->duPort, TRUE, FALSE);
280    }
281    else
282    {
283       ret = getSockAddr(sctpCfg->duIpAddr.ipV6Addr, sctpCfg->duPort, FALSE, FALSE);
284    }
285    if(ret != ROK)
286    {
287       printf("\nUnable to get remote address");
288       RETVALUE(RFAILED);
289    }
290
291    printf("\nStart listening on sockFd %d", lstnSockFd);
292    /* Mark sockFd as being able to accept new associations */
293    error = listen(lstnSockFd, 5);
294    if (error != 0) 
295    {
296       printf("\nListen Failure: %s", strerror(errno));
297       RETVALUE(RFAILED);
298    }
299   
300    while(!connUp)
301    {
302       len = 0;
303       if (!sockFd) 
304       {
305          if ((sockFd = accept(lstnSockFd, &remote_addr.sa, &len)) < 0) 
306          {
307             if(errno == EAGAIN && nonblocking)
308             {
309                sockFd = 0;
310                continue;
311             }
312             printf("\nFailure in accepting connection request. Error: %s", strerror(errno));
313             RETVALUE(RFAILED);
314          }
315          else
316          {
317             /* Mark connection UP */
318             printf("\nCommunication UP. Sock Fd %d", sockFd);
319             connUp = TRUE;
320          }
321       }
322    }
323
324    RETVALUE(ROK);
325 }/* End of sctpConnAccept */
326
327 /*******************************************************************
328  *
329  * @brief Handles an incoming message
330  *
331  * @details
332  *
333  *    Function : sctpInmsgHdlr
334  *
335  *    Functionality:
336  *      Handles an incoming message
337  *
338  * @params[in] Socket file descriptor
339  *             Incoming message header
340  *             Message Length
341  *
342  * @return ROK     - success
343  *         RFAILED - failure
344  *
345  * ****************************************************************/
346 S16 sctpInmsgHdlr(struct msghdr *msg, size_t msgLen)
347 {
348    sctp_cmsg_data_t *data;
349    struct cmsghdr *cmsg;
350    union sctp_notification *sn;
351
352    for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) 
353    {
354       data = (sctp_cmsg_data_t *)CMSG_DATA(cmsg);
355    }
356
357    printf("\nReceived Message");
358    /* if incoming message is data */
359    if (!(MSG_NOTIFICATION & msg->msg_flags)) 
360    {
361       U8 index = 0;
362       char *recvBuf;
363       char *temp = recvBuf;
364       U8 len = msgLen;
365       U8 temp_len;
366       U8 i;
367    
368       /* Extracting the received message */ 
369       while( msgLen > 0)
370       {
371          temp = msg->msg_iov[index].iov_base;
372          temp_len = msg->msg_iov[index].iov_len;
373         
374          if(temp_len > msgLen) 
375          {
376             temp[(temp_len = msgLen) - 1] = '\0';
377          }
378          
379          if((msgLen -= temp_len) > 0) 
380          { 
381            index++;
382          }
383          for (i = 0; i < temp_len-1 ; ++i) 
384          {
385             if (!isprint(temp[i])) 
386                temp[i] = '.';
387          }
388          printf("\nPrinting temp %s", temp);
389          temp = temp + temp_len;
390          index++;
391       }
392       recvBuf[len - 1] = '\0';
393       printf("\n Message: %s temp %s", recvBuf, temp);
394       
395       /* Send received message to cu_app handler */ 
396       cuAppInmsgHdlr(recvBuf, len);
397
398    }
399    else /* If the incoming message is notification */
400    {
401       /* Extract and perform necessary action 
402          Change the connUp state accordingly */
403       union sctp_notification *notify;
404       notify = (union sctp_notification *)msg->msg_iov->iov_base;
405         
406       if (SCTP_ASSOC_CHANGE != notify->sn_header.sn_type) 
407       {
408          printf("\nReceived unexpected notification: %d", notify->sn_header.sn_type);
409          RETVALUE(RFAILED);
410       }
411
412       switch(notify->sn_assoc_change.sac_state)
413       {
414          case SCTP_COMM_UP:
415                 printf("Received SCTP_COMM_UP\n");
416                 break;
417          case SCTP_COMM_LOST:
418                 printf("Received SCTP_COMM_LOST\n");
419                 break;
420          case SCTP_RESTART:
421                 printf("Received SCTP_RESTART\n");
422                 break;
423          case SCTP_SHUTDOWN_COMP:
424                 printf("Received SCTP_SHUTDOWN_COMP\n");
425                 break;
426          case SCTP_CANT_STR_ASSOC:
427                 printf("Received SCTP_CANT_STR_ASSOC\n");
428                 break;
429       }
430    }
431    RETVALUE(ROK);
432 }
433
434 /*******************************************************************
435  *
436  * @brief Receives message on the socket
437  *
438  * @details
439  *
440  *    Function : sctpSockPoll
441  *
442  *    Functionality:
443  *      Receives message on the socket
444  *
445  * @params[in] 
446  * @return ROK     - success
447  *         RFAILED - failure
448  *
449  * ****************************************************************/
450 S16 sctpSockPoll()
451 {
452    U8   error;
453    struct msghdr inmessage;
454    struct iovec iov;
455    char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
456    sockaddr_storage_t msgname;
457
458    /* Initialize inmessage with enough space for DATA... */
459    memset(&inmessage, 0, sizeof(inmessage));
460    if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) 
461    {
462       printf("\n malloc not enough memory!!!");
463       close(sockFd);
464       connUp = FALSE;
465       RETVALUE(RFAILED);
466    }
467    iov.iov_len = REALLY_BIG;
468    inmessage.msg_iov = &iov;
469    inmessage.msg_iovlen = 1;
470    /* or a control message.  */
471    inmessage.msg_control = incmsg;
472    inmessage.msg_controllen = sizeof(incmsg);
473    inmessage.msg_name = &msgname;
474    inmessage.msg_namelen = sizeof(msgname);
475     
476    while (connUp) 
477    {
478       error = recvmsg(sockFd, &inmessage, MSG_WAITALL);
479       if (error < 0) 
480       {
481          if (nonblocking && (EAGAIN == errno)) 
482          {
483             error = 0;
484             continue;
485          }
486          if (socket_type == SOCK_STREAM) 
487          {
488             if (ENOTCONN != errno)
489             {
490                break;
491             }
492             printf("No association is present now!!\n");
493             close(sockFd);
494             sockFd = 0;
495             connUp = FALSE;
496           }
497           break; 
498       }
499       
500       sctpInmsgHdlr(&inmessage, error);
501
502       inmessage.msg_control = incmsg;
503       inmessage.msg_controllen = sizeof(incmsg);
504       inmessage.msg_name = &msgname;
505       inmessage.msg_namelen = sizeof(msgname);
506       iov.iov_len = REALLY_BIG;   
507
508    }/* End of while(connUp) */
509    
510    RETVALUE(ROK);
511 }/* End of sctpSockPoll() */
512
513 /*******************************************************************
514  *
515  * @brief Send message on SCTP socket
516  *
517  * @details
518  *
519  *    Function : sctpOutMsgSend 
520  *
521  *    Functionality:
522  *        Send message on SCTP socket
523  *
524  * @params[in] 
525  * @return ROK     - success
526  *         RFAILED - failure
527  *
528  * ****************************************************************/
529 S16 sctpOutMsgSend(char *message, U8 msglen)
530 {
531    struct msghdr outmsg;
532    struct iovec iov;
533    int error = 0;
534
535    do{
536        if(connUp && msglen != 0)
537        {
538           iov.iov_base = message;
539           iov.iov_len = msglen;
540    
541           outmsg.msg_iov = &iov;
542           outmsg.msg_iovlen = 1;
543           outmsg.msg_control = NULL;
544           outmsg.msg_controllen = 0;
545           outmsg.msg_name = &remote_addr;
546           outmsg.msg_namelen = ra_len;
547           outmsg.msg_flags = 0;
548  
549           error = sendmsg(sockFd, &outmsg, 0);
550         }
551         
552         if(error != msglen)
553         {
554            if(nonblocking && EAGAIN == errno) 
555            {
556               continue;
557            }
558            else
559            {
560               printf("\n Error [%s] while sending message on SCTP assoc", strerror(errno));
561               RETVALUE(RFAILED);
562            }
563         }        
564         else
565         {
566            break;
567         }
568    }while(error != msglen);
569
570    RETVALUE(ROK);
571
572 } /* End of sctpOutMsgSend */
573
574 /*******************************************************************
575  *
576  * @brief SCTP Assoc establishment request from DU
577  *
578  * @details
579  *
580  *    Function : sctpAssocReq
581  *
582  *    Functionality:
583  *          This function opens a socket at DU and
584  *          intiates SCTP connection.
585  *
586  * @params[in]
587  * @return ROK     - success
588  *         RFAILED - failure
589  *
590  * ****************************************************************/
591
592 void sctpStartReq()
593
594    printf("\nStarting CU SCTP");
595
596    /* Open SCTP socket and bind to local address */
597    if(openSctpEndp() != ROK)
598    {
599       printf("\nFailed while opening SCTP endpoint");
600       if(lstnSockFd > 0 )
601       {
602          close(lstnSockFd);
603          lstnSockFd = 0;
604       }
605       /* TODO : Send Assoc establishment failure to cu_app if needed*/
606    }
607    else if(sctpConnAccept() != ROK) /* send connection request */
608    {
609       printf("\nFailed while connecting to peer");
610       close(lstnSockFd);
611       lstnSockFd = 0;
612       assocId = 0;
613       nonblocking = FALSE;
614       /* TODO : Send Assoc establishment failure to cu_app */
615    }
616    else
617    {
618       /* Send AssocCfm to cu_app */
619       if(sctpSockPoll() != ROK)
620       {
621          printf("\nFailed while polling");
622          /* Send failure to cu_app */
623       }
624    }
625 } /* End of sctpStartReq */
626
627 /**********************************************************************
628          End of file
629 **********************************************************************/