From be4a2b5be37d062aeafa7cd501fe77039928f5fc Mon Sep 17 00:00:00 2001 From: Cedric Roux <cedric.roux@eurecom.fr> Date: Thu, 14 Nov 2013 16:26:11 +0000 Subject: [PATCH] - Updated eNB SCTP task to accept new associations in case of "server", for X2AP for example git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4405 818b1a75-f10b-46b9-bf7c-635c3b92a50f --- openair-cn/SCTP/sctp_eNB_itti_messaging.c | 19 ++++ openair-cn/SCTP/sctp_eNB_itti_messaging.h | 4 + openair-cn/SCTP/sctp_eNB_task.c | 109 +++++++++++++++++++++- openair2/COMMON/sctp_messages_def.h | 1 + openair2/COMMON/sctp_messages_types.h | 12 +++ 5 files changed, 144 insertions(+), 1 deletion(-) diff --git a/openair-cn/SCTP/sctp_eNB_itti_messaging.c b/openair-cn/SCTP/sctp_eNB_itti_messaging.c index ffd5b2df3f..336291be37 100644 --- a/openair-cn/SCTP/sctp_eNB_itti_messaging.c +++ b/openair-cn/SCTP/sctp_eNB_itti_messaging.c @@ -45,3 +45,22 @@ int sctp_itti_send_association_resp(task_id_t task_id, instance_t instance, return itti_send_msg_to_task(task_id, instance, message_p); } + +int sctp_itti_send_association_ind(task_id_t task_id, instance_t instance, + int32_t assoc_id, uint16_t port, + uint16_t out_streams, uint16_t in_streams) +{ + MessageDef *message_p; + sctp_new_association_ind_t *sctp_new_association_ind_p; + + message_p = itti_alloc_new_message(TASK_SCTP, SCTP_NEW_ASSOCIATION_IND); + + sctp_new_association_ind_p = &message_p->msg.sctp_new_association_ind; + + sctp_new_association_ind_p->assoc_id = assoc_id; + sctp_new_association_ind_p->port = port; + sctp_new_association_ind_p->out_streams = out_streams; + sctp_new_association_ind_p->in_streams = in_streams; + + return itti_send_msg_to_task(task_id, instance, message_p); +} diff --git a/openair-cn/SCTP/sctp_eNB_itti_messaging.h b/openair-cn/SCTP/sctp_eNB_itti_messaging.h index eba2d19933..a5c5453be9 100644 --- a/openair-cn/SCTP/sctp_eNB_itti_messaging.h +++ b/openair-cn/SCTP/sctp_eNB_itti_messaging.h @@ -9,4 +9,8 @@ int sctp_itti_send_association_resp(task_id_t task_id, instance_t instance, uint16_t cnx_id, enum sctp_state_e state, uint16_t out_streams, uint16_t in_streams); +int sctp_itti_send_association_ind(task_id_t task_id, instance_t instance, + int32_t assoc_id, uint16_t port, + uint16_t out_streams, uint16_t in_streams); + #endif /* SCTP_ITTI_MESSAGING_H_ */ diff --git a/openair-cn/SCTP/sctp_eNB_task.c b/openair-cn/SCTP/sctp_eNB_task.c index c59a185e62..f00acfb71f 100644 --- a/openair-cn/SCTP/sctp_eNB_task.c +++ b/openair-cn/SCTP/sctp_eNB_task.c @@ -49,12 +49,25 @@ #include "sctp_common.h" #include "sctp_eNB_itti_messaging.h" +enum sctp_connection_type_e { + SCTP_TYPE_CLIENT, + SCTP_TYPE_SERVER, + SCTP_TYPE_MAX +}; + struct sctp_cnx_list_elm_s { STAILQ_ENTRY(sctp_cnx_list_elm_s) entries; + /* Type of this association + */ + enum sctp_connection_type_e connection_type; + /* Socket descriptor of connection */ int sd; + /* local port used */ + uint16_t local_port; + /* IN/OUT streams */ uint16_t in_streams; uint16_t out_streams; @@ -113,6 +126,7 @@ void sctp_handle_new_association_req( struct sctp_event_subscribe events; struct sctp_cnx_list_elm_s *sctp_cnx = NULL; + enum sctp_connection_type_e connection_type = SCTP_TYPE_CLIENT; /* Prepare a new SCTP association as requested by upper layer and try to connect * to remote host. @@ -166,6 +180,8 @@ void sctp_handle_new_association_req( * address and port. * Only use IPv4 for the first connection attempt */ + if ((sctp_new_association_req_p->remote_address.ipv6 != 0) || + (sctp_new_association_req_p->remote_address.ipv4 != 0)) { uint8_t address_index = 0; uint8_t used_address = sctp_new_association_req_p->remote_address.ipv6 + @@ -228,10 +244,31 @@ void sctp_handle_new_association_req( return; } } + } else { + /* No remote address provided -> only bind the socket for now. + * Connection will be accepted in the main event loop + */ + struct sockaddr_in6 addr6; + + connection_type = SCTP_TYPE_SERVER; + + /* For now bind to any interface */ + addr6.sin6_family = AF_INET6; + addr6.sin6_addr = in6addr_any; + addr6.sin6_port = htons(sctp_new_association_req_p->port); + + if (bind(sd, (struct sockaddr*)&addr6, sizeof(addr6)) < 0) { + SCTP_ERROR("Failed to bind the socket %d to address any (v4/v6): %s\n", + strerror(errno)); + close(sd); + return; + } } sctp_cnx = calloc(1, sizeof(*sctp_cnx)); + sctp_cnx->connection_type = connection_type; + sctp_cnx->sd = sd; sctp_cnx->task_id = requestor; sctp_cnx->cnx_id = sctp_new_association_req_p->ulp_cnx_id; @@ -283,6 +320,72 @@ void sctp_send_data(instance_t instance, task_id_t task_id, sctp_data_req_t *sct sctp_cnx->assoc_id); } +static +inline void sctp_eNB_accept_associations(struct sctp_cnx_list_elm_s *sctp_cnx) +{ + int client_sd; + + struct sockaddr saddr; + socklen_t saddr_size; + + DevAssert(sctp_cnx != NULL); + + saddr_size = sizeof(saddr); + + /* There is a new client connecting. Accept it... + */ + if ((client_sd = accept(sctp_cnx->sd, &saddr, &saddr_size)) < 0) { + SCTP_ERROR("[%d] accept failed: %s:%d\n", sctp_cnx->sd, strerror(errno), errno); + } else { + struct sctp_cnx_list_elm_s *new_cnx; + uint16_t port; + + /* This is an ipv6 socket */ + port = ((struct sockaddr_in6*)&saddr)->sin6_port; + + /* Contrary to BSD, client socket does not inherit O_NONBLOCK option */ + if (fcntl(client_sd, F_SETFL, O_NONBLOCK) < 0) { + SCTP_ERROR("fcntl F_SETFL O_NONBLOCK failed: %s\n", + strerror(errno)); + close(client_sd); + return; + } + + new_cnx = calloc(1, sizeof(*sctp_cnx)); + + DevAssert(new_cnx != NULL); + + new_cnx->connection_type = SCTP_TYPE_CLIENT; + + new_cnx->sd = client_sd; + new_cnx->task_id = sctp_cnx->task_id; + new_cnx->cnx_id = 0; + new_cnx->ppid = sctp_cnx->ppid; + new_cnx->instance = sctp_cnx->instance; + new_cnx->local_port = sctp_cnx->local_port; + + if (sctp_get_sockinfo(client_sd, &new_cnx->in_streams, &new_cnx->out_streams, + &new_cnx->assoc_id) != 0) + { + SCTP_ERROR("sctp_get_sockinfo failed\n"); + close(client_sd); + free(new_cnx); + return; + } + + /* Insert new element at end of list */ + STAILQ_INSERT_TAIL(&sctp_cnx_list, new_cnx, entries); + sctp_nb_cnx++; + + /* Add the socket to list of fd monitored by ITTI */ + itti_subscribe_event_fd(TASK_SCTP, client_sd); + + sctp_itti_send_association_ind(new_cnx->task_id, new_cnx->instance, + new_cnx->assoc_id, port, + new_cnx->out_streams, new_cnx->in_streams); + } +} + static inline void sctp_eNB_read_from_socket(struct sctp_cnx_list_elm_s *sctp_cnx) { @@ -387,7 +490,11 @@ void sctp_eNB_flush_sockets(struct epoll_event *events, int nb_events) continue; } SCTP_DEBUG("Found data for descriptor %d\n", events[i].data.fd); - sctp_eNB_read_from_socket(sctp_cnx); + if (sctp_cnx->connection_type == SCTP_TYPE_CLIENT) { + sctp_eNB_read_from_socket(sctp_cnx); + } else { + sctp_eNB_accept_associations(sctp_cnx); + } } } diff --git a/openair2/COMMON/sctp_messages_def.h b/openair2/COMMON/sctp_messages_def.h index c009e39638..4c3450e18d 100644 --- a/openair2/COMMON/sctp_messages_def.h +++ b/openair2/COMMON/sctp_messages_def.h @@ -1,5 +1,6 @@ MESSAGE_DEF(SCTP_NEW_ASSOCIATION_REQ , MESSAGE_PRIORITY_MED, sctp_new_association_req_t , sctp_new_association_req) MESSAGE_DEF(SCTP_NEW_ASSOCIATION_RESP, MESSAGE_PRIORITY_MED, sctp_new_association_resp_t , sctp_new_association_resp) +MESSAGE_DEF(SCTP_NEW_ASSOCIATION_IND , MESSAGE_PRIORITY_MED, sctp_new_association_ind_t , sctp_new_association_ind) MESSAGE_DEF(SCTP_REGISTER_UPPER_LAYER, MESSAGE_PRIORITY_MED, sctp_listener_register_upper_layer_t, sctp_listener_register_upper_layer) MESSAGE_DEF(SCTP_DATA_REQ, MESSAGE_PRIORITY_MED, sctp_data_req_t , sctp_data_req) MESSAGE_DEF(SCTP_DATA_IND, MESSAGE_PRIORITY_MED, sctp_data_ind_t , sctp_data_ind) \ No newline at end of file diff --git a/openair2/COMMON/sctp_messages_types.h b/openair2/COMMON/sctp_messages_types.h index 1c2dc9199c..96080a0b0a 100644 --- a/openair2/COMMON/sctp_messages_types.h +++ b/openair2/COMMON/sctp_messages_types.h @@ -23,6 +23,18 @@ typedef struct { net_ip_address_t remote_address; } sctp_new_association_req_t; +typedef struct { + /* Assoc id of the new association */ + int32_t assoc_id; + + /* The port used by remote host */ + uint16_t port; + + /* Number of streams used for this association */ + uint16_t in_streams; + uint16_t out_streams; +} sctp_new_association_ind_t; + typedef struct { /* Upper layer connexion identifier */ uint16_t ulp_cnx_id; -- 2.26.2