1 /*******************************************************************************
2 ################################################################################
3 # Copyright (c) [2017-2019] [Radisys] #
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 #
9 # http://www.apache.org/licenses/LICENSE-2.0 #
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 *******************************************************************************/
19 /* This file contains all SCTP related functionality */
23 #include <sys/types.h>
24 #include <sys/socket.h>
30 /* Global variable declaration */
38 sockaddr_storage_t local_addr;
39 sockaddr_storage_t remote_addr;
45 /**************************************************************************
46 * @brief Task Initiation callback function.
50 * Function : sctpActvInit
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.
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
61 * @param[in] Reason reason.
62 * @return ROK - success
64 ***************************************************************************/
65 S16 sctpActvInit(Ent entity, Inst inst, Region region, Reason reason)
72 sctpCfg = &(cuCfgParams.sctpParams);
77 /**************************************************************************
78 * @brief Task Activation callback function.
82 * Function : sctpActvTsk
85 * This function handles all SCTP messages received
86 * This API is registered with SSI during the
87 * Task Registration of DU APP.
89 * @param[in] Pst *pst, Post structure of the primitive.
90 * @param[in] Buffer *mBuf, Packed primitive parameters in the
92 * @return ROK - success
95 ***************************************************************************/
96 S16 sctpActvTsk(Pst *pst, Buffer *mBuf)
103 /*******************************************************************
105 * @brief Converts internet address to sockaddr type
109 * Function : getSockAddr
112 * Converts internet address to sockaddr type
115 * @return ROK - success
118 * ****************************************************************/
120 S16 getSockAddr(char *hostIp, U16 portNum, Bool ipv4Pres, Bool local)
122 sockaddr_storage_t address;
123 struct hostent *host;
127 /* Getting the transport address for local host name */
130 host = gethostbyname(hostIp);
131 if (host == NULL || host->h_length < 1)
133 printf("\nBad hostname: %s", hostIp);
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);
143 host = gethostbyname2(hostIp, AF_INET6);
144 if (host == NULL || host->h_length < 1)
146 printf("\n Bad hostname: %s", hostIp);
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;
156 memcpy((U8 *)la_raw, (U8 *)host->h_addr_list[0], host->h_length);
160 local_addr = address;
165 remote_addr = address;
170 } /* End of getSockAddr() */
172 /*******************************************************************
174 * @brief Opens a non-blocking socket and binds to local address
178 * Function : openSctpEndp
181 * Opens a non-blocking socket and binds to local address
184 * @return ROK - success
187 * ****************************************************************/
190 sa_family_t la_family;
194 printf("\nEntering openSctpEndp");
196 /* Getting the transport address for local host name */
197 if(sctpCfg->cuIpAddr.ipV4Pres)
199 printf("\nLocal Host Address %s",cuCfgParams.sctpParams.cuIpAddr.ipV4Addr);
200 if(getSockAddr(sctpCfg->cuIpAddr.ipV4Addr, sctpCfg->cuPort, TRUE, TRUE) != ROK )
202 printf("\nUnable to get local address");
205 la_len = sizeof(local_addr.v4);
210 if(getSockAddr(sctpCfg->cuIpAddr.ipV6Addr, sctpCfg->cuPort, FALSE, TRUE) != ROK )
212 printf("\nUnable to get local address");
215 la_len = sizeof(local_addr.v6);
216 la_family = AF_INET6;
219 socket_type = SOCK_STREAM;
221 /* Creating new end point */
222 lstnSockFd = socket(la_family, socket_type, IPPROTO_SCTP);
225 printf("\n Failed to create socket %s", strerror(errno));
229 /* Binding socket to local address and port */
230 error = bind(lstnSockFd, &local_addr.sa, la_len);
233 printf("\n Failed to bind to socket. Error [%s]", strerror(errno));
237 /* Setting socket as non-blocking*/
238 error = fcntl(lstnSockFd, F_SETFL, O_NONBLOCK);
241 printf("\n Failed to set socket as non blocking. Error [%s]", strerror(errno));
251 } /* End of openSctpEndp() */
253 /*******************************************************************
255 * @brief Listens for connection request from peer SCTP
259 * Function : sctpConnAccept
262 * Listens and accepts SCTP connection request from peer.
263 * Here, DU-SCTP will initate connection towards CU-SCTP
266 * @return ROK - success
269 * ****************************************************************/
276 /* Getting the transport address for remote host name */
277 if(sctpCfg->duIpAddr.ipV4Pres)
279 ret = getSockAddr(sctpCfg->duIpAddr.ipV4Addr, sctpCfg->duPort, TRUE, FALSE);
283 ret = getSockAddr(sctpCfg->duIpAddr.ipV6Addr, sctpCfg->duPort, FALSE, FALSE);
287 printf("\nUnable to get remote address");
291 printf("\nStart listening on sockFd %d", lstnSockFd);
292 /* Mark sockFd as being able to accept new associations */
293 error = listen(lstnSockFd, 5);
296 printf("\nListen Failure: %s", strerror(errno));
305 if ((sockFd = accept(lstnSockFd, &remote_addr.sa, &len)) < 0)
307 if(errno == EAGAIN && nonblocking)
312 printf("\nFailure in accepting connection request. Error: %s", strerror(errno));
317 /* Mark connection UP */
318 printf("\nCommunication UP. Sock Fd %d", sockFd);
325 }/* End of sctpConnAccept */
327 /*******************************************************************
329 * @brief Handles an incoming message
333 * Function : sctpInmsgHdlr
336 * Handles an incoming message
338 * @params[in] Socket file descriptor
339 * Incoming message header
342 * @return ROK - success
345 * ****************************************************************/
346 S16 sctpInmsgHdlr(struct msghdr *msg, size_t msgLen)
348 sctp_cmsg_data_t *data;
349 struct cmsghdr *cmsg;
350 union sctp_notification *sn;
352 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
354 data = (sctp_cmsg_data_t *)CMSG_DATA(cmsg);
357 printf("\nReceived Message");
358 /* if incoming message is data */
359 if (!(MSG_NOTIFICATION & msg->msg_flags))
363 char *temp = recvBuf;
368 /* Extracting the received message */
371 temp = msg->msg_iov[index].iov_base;
372 temp_len = msg->msg_iov[index].iov_len;
374 if(temp_len > msgLen)
376 temp[(temp_len = msgLen) - 1] = '\0';
379 if((msgLen -= temp_len) > 0)
383 for (i = 0; i < temp_len-1 ; ++i)
385 if (!isprint(temp[i]))
388 printf("\nPrinting temp %s", temp);
389 temp = temp + temp_len;
392 recvBuf[len - 1] = '\0';
393 printf("\n Message: %s temp %s", recvBuf, temp);
395 /* Send received message to cu_app handler */
396 cuAppInmsgHdlr(recvBuf, len);
399 else /* If the incoming message is notification */
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;
406 if (SCTP_ASSOC_CHANGE != notify->sn_header.sn_type)
408 printf("\nReceived unexpected notification: %d", notify->sn_header.sn_type);
412 switch(notify->sn_assoc_change.sac_state)
415 printf("Received SCTP_COMM_UP\n");
418 printf("Received SCTP_COMM_LOST\n");
421 printf("Received SCTP_RESTART\n");
423 case SCTP_SHUTDOWN_COMP:
424 printf("Received SCTP_SHUTDOWN_COMP\n");
426 case SCTP_CANT_STR_ASSOC:
427 printf("Received SCTP_CANT_STR_ASSOC\n");
434 /*******************************************************************
436 * @brief Receives message on the socket
440 * Function : sctpSockPoll
443 * Receives message on the socket
446 * @return ROK - success
449 * ****************************************************************/
453 struct msghdr inmessage;
455 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
456 sockaddr_storage_t msgname;
458 /* Initialize inmessage with enough space for DATA... */
459 memset(&inmessage, 0, sizeof(inmessage));
460 if ((iov.iov_base = malloc(REALLY_BIG)) == NULL)
462 printf("\n malloc not enough memory!!!");
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);
478 error = recvmsg(sockFd, &inmessage, MSG_WAITALL);
481 if (nonblocking && (EAGAIN == errno))
486 if (socket_type == SOCK_STREAM)
488 if (ENOTCONN != errno)
492 printf("No association is present now!!\n");
500 sctpInmsgHdlr(&inmessage, error);
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;
508 }/* End of while(connUp) */
511 }/* End of sctpSockPoll() */
513 /*******************************************************************
515 * @brief Send message on SCTP socket
519 * Function : sctpOutMsgSend
522 * Send message on SCTP socket
525 * @return ROK - success
528 * ****************************************************************/
529 S16 sctpOutMsgSend(char *message, U8 msglen)
531 struct msghdr outmsg;
536 if(connUp && msglen != 0)
538 iov.iov_base = message;
539 iov.iov_len = msglen;
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;
549 error = sendmsg(sockFd, &outmsg, 0);
554 if(nonblocking && EAGAIN == errno)
560 printf("\n Error [%s] while sending message on SCTP assoc", strerror(errno));
568 }while(error != msglen);
572 } /* End of sctpOutMsgSend */
574 /*******************************************************************
576 * @brief SCTP Assoc establishment request from DU
580 * Function : sctpAssocReq
583 * This function opens a socket at DU and
584 * intiates SCTP connection.
587 * @return ROK - success
590 * ****************************************************************/
594 printf("\nStarting CU SCTP");
596 /* Open SCTP socket and bind to local address */
597 if(openSctpEndp() != ROK)
599 printf("\nFailed while opening SCTP endpoint");
605 /* TODO : Send Assoc establishment failure to cu_app if needed*/
607 else if(sctpConnAccept() != ROK) /* send connection request */
609 printf("\nFailed while connecting to peer");
614 /* TODO : Send Assoc establishment failure to cu_app */
618 /* Send AssocCfm to cu_app */
619 if(sctpSockPoll() != ROK)
621 printf("\nFailed while polling");
622 /* Send failure to cu_app */
625 } /* End of sctpStartReq */
627 /**********************************************************************
629 **********************************************************************/