Commit 6cbd85f3 authored by Lionel Gauthier's avatar Lionel Gauthier

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5438 818b1a75-f10b-46b9-bf7c-635c3b92a50f
parent 2e698946
......@@ -55,51 +55,49 @@
#include "sctp_common.h"
#include "sctp_eNB_itti_messaging.h"
/* Used to format an uint32_t containing an ipv4 address */
#define IPV4_ADDR "%u.%u.%u.%u"
#define IPV4_ADDR_FORMAT(aDDRESS) \
(uint8_t)((aDDRESS) & 0x000000ff), \
(uint8_t)(((aDDRESS) & 0x0000ff00) >> 8 ), \
(uint8_t)(((aDDRESS) & 0x00ff0000) >> 16), \
(uint8_t)(((aDDRESS) & 0xff000000) >> 24)
enum sctp_connection_type_e {
SCTP_TYPE_CLIENT,
SCTP_TYPE_SERVER,
SCTP_TYPE_MAX
};
struct sctp_cnx_list_elm_s {
typedef 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;
/* Configured PPID */
uint16_t ppid;
/* Association id */
int32_t assoc_id;
/* Nb of messages received on interface */
uint32_t nb_messages;
int sd; ///< Socket descriptor of connection */
uint16_t local_port;
uint16_t in_streams; ///< Number of input streams negociated for this connection
uint16_t out_streams; ///< Number of output streams negotiated for this connection
uint16_t ppid; ///< Payload protocol Identifier
int32_t assoc_id; ///< SCTP association id for the connection
uint32_t messages_recv; ///< Number of messages received on this connection
uint32_t messages_sent; ///< Number of messages sent on this connection
task_id_t task_id; ///< Task id of the task who asked for this connection
instance_t instance; ///< Instance
uint16_t cnx_id; ///< Upper layer identifier
/* Task id of the task who asked for this connection */
task_id_t task_id;
struct sockaddr *peer_addresses;///< A list of peer addresses for server socket
int nb_peer_addresses; ///< For server socket
} sctp_cnx_list_elm_t;
/* Instance */
instance_t instance;
/* Upper layer identifier */
uint16_t cnx_id;
};
static STAILQ_HEAD(sctp_cnx_list_head, sctp_cnx_list_elm_s) sctp_cnx_list;
static uint16_t sctp_nb_cnx = 0;
struct sctp_cnx_list_elm_s *sctp_get_cnx(int32_t assoc_id, int sd)
{
struct sctp_cnx_list_elm_s *elm;
......@@ -144,7 +142,15 @@ void sctp_handle_new_association_req(
DevAssert(sctp_new_association_req_p != NULL);
/* Create new socket with IPv6 affinity */
#ifdef NO_VIRTUAL_MACHINE
// in init chunk appears a list of host addresses, IPv4 and IPv4 in an arbitrary (unsorted) order
// SCTP hearbeats starts with first ipv4 addresses then stop triyng with other ipv4 addresses
// if it encounters an IPv6 address in list, so we can force the building of IPv4 addresses only
// with AF_INET (of cource the working IPv4 address is the last in the list...)
if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
#else
if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
#endif
SCTP_ERROR("Socket creation failed: %s\n", strerror(errno));
return;
}
......@@ -193,7 +199,7 @@ void sctp_handle_new_association_req(
if (s > 0 ) {
if (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr == in.s_addr) {
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), ifa->ifa_name);
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s",ifa->ifa_name);
if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
SCTP_ERROR("Setsockopt SOL_SOCKET failed: %s\n",
strerror(errno));
......@@ -213,7 +219,7 @@ void sctp_handle_new_association_req(
if (memcmp(&((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr,
&in6, sizeof(in6)) == 0) {
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), ifa->ifa_name);
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", ifa->ifa_name);
if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
SCTP_ERROR("Setsockopt SOL_SOCKET failed: %s\n",
strerror(errno));
......@@ -304,8 +310,13 @@ void sctp_handle_new_association_req(
close(sd);
return;
} else {
SCTP_DEBUG("connectx %d in progress...\n", assoc_id);
SCTP_DEBUG("connectx assoc_id %d in progress..., used %d addresses\n",
assoc_id, used_address);
}
} else {
SCTP_DEBUG("sctp_connectx SUCCESS, used %d addresses assoc_id %d\n",
used_address,
assoc_id);
}
} else {
/* No remote address provided -> only bind the socket for now.
......@@ -347,7 +358,10 @@ void sctp_handle_new_association_req(
sd, sctp_nb_cnx, assoc_id);
}
void sctp_send_data(instance_t instance, task_id_t task_id, sctp_data_req_t *sctp_data_req_p)
void sctp_send_data(
instance_t instance,
task_id_t task_id,
sctp_data_req_t *sctp_data_req_p)
{
struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
......@@ -384,6 +398,122 @@ void sctp_send_data(instance_t instance, task_id_t task_id, sctp_data_req_t *sct
sctp_cnx->assoc_id);
}
static int sctp_create_new_listener(
const instance_t instance,
const task_id_t requestor,
sctp_init_t *init_p)
{
struct sctp_event_subscribe event;
struct sockaddr *addr = NULL;
struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
uint16_t i = 0, j = 0;
int sd = 0;
int used_addresses = 0;
DevAssert(init_p != NULL);
if (init_p->ipv4 == 0 && init_p->ipv6 == 0) {
SCTP_ERROR("Illegal IP configuration upper layer should request at"
"least ipv4 and/or ipv6 config\n");
return -1;
}
if ((used_addresses = init_p->nb_ipv4_addr + init_p->nb_ipv6_addr) == 0) {
SCTP_WARN("No address provided...\n");
return -1;
}
addr = calloc(used_addresses, sizeof(struct sockaddr));
SCTP_DEBUG("Creating new listen socket on port %u with\n", init_p->port);
if (init_p->ipv4 == 1) {
struct sockaddr_in *ip4_addr;
SCTP_DEBUG("ipv4 addresses:\n");
for (i = 0; i < init_p->nb_ipv4_addr; i++) {
SCTP_DEBUG("\t- "IPV4_ADDR"\n",
IPV4_ADDR_FORMAT(init_p->ipv4_address[i]));
ip4_addr = (struct sockaddr_in *)&addr[i];
ip4_addr->sin_family = AF_INET;
ip4_addr->sin_port = htons(init_p->port);
ip4_addr->sin_addr.s_addr = init_p->ipv4_address[i];
}
}
if (init_p->ipv6 == 1) {
struct sockaddr_in6 *ip6_addr;
SCTP_DEBUG("ipv6 addresses:\n");
for (j = 0; j < init_p->nb_ipv6_addr; j++) {
SCTP_DEBUG("\t- %s\n", init_p->ipv6_address[j]);
ip6_addr = (struct sockaddr_in6 *)&addr[i + j];
ip6_addr->sin6_family = AF_INET6;
ip6_addr->sin6_port = htons(init_p->port);
if (inet_pton(AF_INET6, init_p->ipv6_address[j],
ip6_addr->sin6_addr.s6_addr) <= 0) {
SCTP_WARN("Provided ipv6 address %s is not valid\n",
init_p->ipv6_address[j]);
}
}
}
if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno);
return -1;
}
memset((void *)&event, 1, sizeof(struct sctp_event_subscribe));
if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &event,
sizeof(struct sctp_event_subscribe)) < 0) {
SCTP_ERROR("setsockopt: %s:%d\n", strerror(errno), errno);
return -1;
}
sctp_cnx = calloc(1, sizeof(*sctp_cnx));
sctp_cnx->connection_type = SCTP_TYPE_SERVER;
sctp_cnx->sd = sd;
sctp_cnx->local_port = init_p->port;
sctp_cnx->in_streams = 32;
sctp_cnx->out_streams = 32;
sctp_cnx->ppid = init_p->ppid;
sctp_cnx->task_id = requestor;
sctp_cnx->instance = instance;
/* Some pre-bind socket configuration */
if (sctp_set_init_opt(sd,
sctp_cnx->in_streams,
sctp_cnx->out_streams,
0,
0) < 0)
{
goto err;
}
if (sctp_bindx(sd, addr, used_addresses, SCTP_BINDX_ADD_ADDR) != 0) {
SCTP_ERROR("sctp_bindx: %s:%d\n", strerror(errno), errno);
return -1;
}
if (listen(sd, 5) < 0) {
SCTP_ERROR("listen: %s:%d\n", strerror(errno), errno);
return -1;
}
/* Insert new element at end of list */
STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
sctp_nb_cnx++;
/* Add the socket to list of fd monitored by ITTI */
itti_subscribe_event_fd(TASK_SCTP, sd);
return sd;
err:
if (sd != -1) {
close(sd);
sd = -1;
}
return -1;
}
static
inline void sctp_eNB_accept_associations(struct sctp_cnx_list_elm_s *sctp_cnx)
{
......@@ -547,7 +677,7 @@ inline void sctp_eNB_read_from_socket(struct sctp_cnx_list_elm_s *sctp_cnx)
}
}
} else {
sctp_cnx->nb_messages++;
sctp_cnx->messages_recv++;
if (ntohl(sinfo.sinfo_ppid) != sctp_cnx->ppid) {
/* Mismatch in Payload Protocol Identifier,
......@@ -590,6 +720,7 @@ void sctp_eNB_flush_sockets(struct epoll_event *events, int nb_events)
}
}
void *sctp_eNB_task(void *arg)
{
int nb_events;
......@@ -610,9 +741,24 @@ void *sctp_eNB_task(void *arg)
if (received_msg != NULL) {
switch (ITTI_MSG_ID(received_msg))
{
case SCTP_INIT_MSG: {
SCTP_DEBUG("Received SCTP_INIT_MSG\n");
/* We received a new connection request */
if (sctp_create_new_listener(
ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
&received_msg->ittiMsg.sctp_init) < 0) {
/* SCTP socket creation or bind failed... */
SCTP_ERROR("Failed to create new SCTP listener\n");
}
} break;
case SCTP_CLOSE_ASSOCIATION:
break;
case TERMINATE_MESSAGE:
itti_exit_task();
break;
case SCTP_NEW_ASSOCIATION_REQ: {
sctp_handle_new_association_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
ITTI_MSG_ORIGIN_ID(received_msg),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment