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