sctp_eNB_task.c 42.5 KB
Newer Older
1 2 3 4 5
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

22 23 24 25
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
26 27
#include <unistd.h>
#include <fcntl.h>
28 29 30

#include <sys/types.h>
#include <sys/socket.h>
31 32 33 34 35
#include <netdb.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <sys/ioctl.h>
#include <net/if.h>
36 37 38 39 40 41 42

#include <netinet/in.h>
#include <netinet/sctp.h>

#include <arpa/inet.h>

#include "assertions.h"
laurent's avatar
laurent committed
43
#include "common/utils/system.h"
44 45 46 47
#include "queue.h"

#include "intertask_interface.h"

48
#include "sctp_default_values.h"
49 50 51
#include "sctp_common.h"
#include "sctp_eNB_itti_messaging.h"

Lionel Gauthier's avatar
 
Lionel Gauthier committed
52 53 54 55 56 57 58 59 60
/* 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)


61
enum sctp_connection_type_e {
frtabu's avatar
frtabu committed
62 63 64 65
    SCTP_TYPE_CLIENT,
    SCTP_TYPE_SERVER,
    SCTP_TYPE_MULTI_SERVER,
    SCTP_TYPE_MAX
66 67
};

Lionel Gauthier's avatar
 
Lionel Gauthier committed
68
typedef struct sctp_cnx_list_elm_s {
frtabu's avatar
frtabu committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
    STAILQ_ENTRY(sctp_cnx_list_elm_s) entries;

    /* Type of this association
     */
    enum sctp_connection_type_e connection_type;

    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     (note4debug host byte order)
    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

    struct   sockaddr *peer_addresses;///< A list of peer addresses for server socket
    int      nb_peer_addresses; ///< For server socket
Lionel Gauthier's avatar
 
Lionel Gauthier committed
89
} sctp_cnx_list_elm_t;
90 91 92 93 94


static STAILQ_HEAD(sctp_cnx_list_head, sctp_cnx_list_elm_s) sctp_cnx_list;
static uint16_t sctp_nb_cnx = 0;

95
//------------------------------------------------------------------------------
96 97
struct sctp_cnx_list_elm_s *sctp_get_cnx(int32_t assoc_id, int sd)
{
frtabu's avatar
frtabu committed
98
    struct sctp_cnx_list_elm_s *elm;
99

frtabu's avatar
frtabu committed
100 101 102 103 104 105 106 107 108 109
    STAILQ_FOREACH(elm, &sctp_cnx_list, entries) {
        if (assoc_id != -1) {
            if (elm->assoc_id == assoc_id) {
                return elm;
            }
        } else {
            if (elm->sd == sd) {
                return elm;
            }
        }
110 111
    }

frtabu's avatar
frtabu committed
112
    return NULL;
113 114
}

115 116 117 118
//------------------------------------------------------------------------------
static inline
void
sctp_eNB_accept_associations_multi(
frtabu's avatar
frtabu committed
119
    struct sctp_cnx_list_elm_s *sctp_cnx)
120
{
frtabu's avatar
frtabu committed
121 122 123 124 125
    int                    ns;
    int                    n;
    int                    flags = 0;
    socklen_t              from_len;
    struct sctp_sndrcvinfo sinfo;
126

frtabu's avatar
frtabu committed
127 128
    struct sockaddr_in addr;
    uint8_t buffer[SCTP_RECV_BUFFER_SIZE];
129

frtabu's avatar
frtabu committed
130
    DevAssert(sctp_cnx != NULL);
131

frtabu's avatar
frtabu committed
132 133 134
    memset((void *)&addr, 0, sizeof(struct sockaddr_in));
    from_len = (socklen_t)sizeof(struct sockaddr_in);
    memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
135

frtabu's avatar
frtabu committed
136 137 138
    n = sctp_recvmsg(sctp_cnx->sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE,
                     (struct sockaddr *)&addr, &from_len,
                     &sinfo, &flags);
139

frtabu's avatar
frtabu committed
140 141 142 143 144 145 146 147 148
    if (n < 0) {
        if (errno == ENOTCONN) {
            SCTP_DEBUG("Received not connected for sd %d\n", sctp_cnx->sd);
            close(sctp_cnx->sd);
        } else {
            SCTP_DEBUG("An error occured during read\n");
            SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno);
        }
        return;
149 150
    }

frtabu's avatar
frtabu committed
151 152 153
    if (flags & MSG_NOTIFICATION) {
        union sctp_notification *snp;
        snp = (union sctp_notification *)buffer;
154

frtabu's avatar
frtabu committed
155 156
        SCTP_DEBUG("Received notification for sd %d, type %u\n",
                   sctp_cnx->sd, snp->sn_header.sn_type);
157

frtabu's avatar
frtabu committed
158 159 160 161
        /* Association has changed. */
        if (SCTP_ASSOC_CHANGE == snp->sn_header.sn_type) {
            struct sctp_assoc_change *sctp_assoc_changed;
            sctp_assoc_changed = &snp->sn_assoc_change;
162

frtabu's avatar
frtabu committed
163
            SCTP_DEBUG("Client association changed: %d\n", sctp_assoc_changed->sac_state);
164

frtabu's avatar
frtabu committed
165 166 167 168 169 170
            /* New physical association requested by a peer */
            switch (sctp_assoc_changed->sac_state) {
            case SCTP_COMM_UP: {
                SCTP_DEBUG("Comm up notified for sd %d, assigned assoc_id %d\n",
                           sctp_cnx->sd, sctp_assoc_changed->sac_assoc_id);
                struct sctp_cnx_list_elm_s *new_cnx;
171

frtabu's avatar
frtabu committed
172
                new_cnx = calloc(1, sizeof(*sctp_cnx));
173

frtabu's avatar
frtabu committed
174
                DevAssert(new_cnx != NULL);
175

frtabu's avatar
frtabu committed
176
                new_cnx->connection_type = SCTP_TYPE_CLIENT;
177

frtabu's avatar
frtabu committed
178
                ns = sctp_peeloff(sctp_cnx->sd, sctp_assoc_changed->sac_assoc_id);
179

frtabu's avatar
frtabu committed
180 181 182 183 184 185 186
                new_cnx->sd         = ns;
                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;
                new_cnx->assoc_id   = sctp_assoc_changed->sac_assoc_id;
187

frtabu's avatar
frtabu committed
188 189 190 191 192 193 194
                if (sctp_get_sockinfo(ns, &new_cnx->in_streams, &new_cnx->out_streams,
                                      &new_cnx->assoc_id) != 0) {
                    SCTP_ERROR("sctp_get_sockinfo failed\n");
                    close(ns);
                    free(new_cnx);
                    return;
                }
195

frtabu's avatar
frtabu committed
196 197 198
                /* Insert new element at end of list */
                STAILQ_INSERT_TAIL(&sctp_cnx_list, new_cnx, entries);
                sctp_nb_cnx++;
199

frtabu's avatar
frtabu committed
200 201
                /* Add the socket to list of fd monitored by ITTI */
                itti_subscribe_event_fd(TASK_SCTP, ns);
202

frtabu's avatar
frtabu committed
203 204 205 206 207
                sctp_itti_send_association_ind(new_cnx->task_id, new_cnx->instance,
                                               new_cnx->assoc_id, new_cnx->local_port,
                                               new_cnx->out_streams, new_cnx->in_streams);
            }
            break;
208

frtabu's avatar
frtabu committed
209 210 211 212 213 214
            default:
                break;
            }
        }
    } else {
        SCTP_DEBUG("No notification from SCTP\n");
215 216 217 218
    }
}

//------------------------------------------------------------------------------
laurent's avatar
laurent committed
219
static void
220
sctp_handle_new_association_req_multi(
frtabu's avatar
frtabu committed
221 222 223
    const instance_t instance,
    const task_id_t requestor,
    const sctp_new_association_req_multi_t * const sctp_new_association_req_p)
224
{
frtabu's avatar
frtabu committed
225 226
    int                           ns;
    int sd;
227

frtabu's avatar
frtabu committed
228
    int32_t                       assoc_id = 0;
229

frtabu's avatar
frtabu committed
230 231
    struct sctp_cnx_list_elm_s   *sctp_cnx = NULL;
    enum sctp_connection_type_e   connection_type = SCTP_TYPE_CLIENT;
232

frtabu's avatar
frtabu committed
233 234 235 236
    /* Prepare a new SCTP association as requested by upper layer and try to connect
     * to remote host.
     */
    DevAssert(sctp_new_association_req_p != NULL);
237

frtabu's avatar
frtabu committed
238
    sd = sctp_new_association_req_p->multi_sd;
239

frtabu's avatar
frtabu committed
240
    /* Create new socket with IPv6 affinity */
241 242
//#warning "SCTP may Force IPv4 only, here"

frtabu's avatar
frtabu committed
243 244
    /* Mark the socket as non-blocking */
    //if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0) {
245
    //SCTP_ERROR("fcntl F_SETFL O_NONBLOCK failed: %s\n",
frtabu's avatar
frtabu committed
246
    //         strerror(errno));
247 248
    //close(sd);
    //return;
frtabu's avatar
frtabu committed
249
    //}
250

frtabu's avatar
frtabu committed
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    /* SOCK_STREAM socket type requires an explicit connect to the remote host
     * 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 +
                                sctp_new_association_req_p->remote_address.ipv4;
        struct sockaddr_in addr[used_address];

        memset(addr, 0, used_address * sizeof(struct sockaddr_in));

        if (sctp_new_association_req_p->remote_address.ipv6 == 1) {
            if (inet_pton(AF_INET6, sctp_new_association_req_p->remote_address.ipv6_address,
                          &addr[address_index].sin_addr.s_addr) != 1) {
                SCTP_ERROR("Failed to convert ipv6 address %*s to network type\n",
                           (int)strlen(sctp_new_association_req_p->remote_address.ipv6_address),
                           sctp_new_association_req_p->remote_address.ipv6_address);
                //close(sd);
                //return;
272
                exit_fun("sctp_handle_new_association_req_multi fatal: inet_pton error");
frtabu's avatar
frtabu committed
273 274 275 276 277 278 279 280 281 282
            }

            SCTP_DEBUG("Converted ipv6 address %*s to network type\n",
                       (int)strlen(sctp_new_association_req_p->remote_address.ipv6_address),
                       sctp_new_association_req_p->remote_address.ipv6_address);

            addr[address_index].sin_family = AF_INET6;
            addr[address_index].sin_port   = htons(sctp_new_association_req_p->port);
            address_index++;
        }
283

frtabu's avatar
frtabu committed
284 285 286 287 288 289 290 291
        if (sctp_new_association_req_p->remote_address.ipv4 == 1) {
            if (inet_pton(AF_INET, sctp_new_association_req_p->remote_address.ipv4_address,
                          &addr[address_index].sin_addr.s_addr) != 1) {
                SCTP_ERROR("Failed to convert ipv4 address %*s to network type\n",
                           (int)strlen(sctp_new_association_req_p->remote_address.ipv4_address),
                           sctp_new_association_req_p->remote_address.ipv4_address);
                //close(sd);
                //return;
292
                exit_fun("sctp_handle_new_association_req_multi fatal: inet_pton error");
frtabu's avatar
frtabu committed
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
            }

            SCTP_DEBUG("Converted ipv4 address %*s to network type\n",
                       (int)strlen(sctp_new_association_req_p->remote_address.ipv4_address),
                       sctp_new_association_req_p->remote_address.ipv4_address);

            addr[address_index].sin_family = AF_INET;
            addr[address_index].sin_port   = htons(sctp_new_association_req_p->port);
            address_index++;
        }

        /* Connect to remote host and port */
        if (sctp_connectx(sd, (struct sockaddr *)addr, 1, &assoc_id) < 0) {
            /* sctp_connectx on non-blocking socket return EINPROGRESS */
            if (errno != EINPROGRESS) {
                SCTP_ERROR("Connect failed: %s\n", strerror(errno));
                sctp_itti_send_association_resp(
                    requestor, instance, -1, sctp_new_association_req_p->ulp_cnx_id,
                    SCTP_STATE_UNREACHABLE, 0, 0);
                /* Add the socket to list of fd monitored by ITTI */
                //itti_unsubscribe_event_fd(TASK_SCTP, sd);
                //close(sd);
                return;
            } else {
                SCTP_DEBUG("connectx assoc_id  %d in progress..., used %d addresses\n",
                           assoc_id, used_address);
            }
        } else {
Laurent Thomas's avatar
Laurent Thomas committed
321 322
            SCTP_DEBUG("sctp_connectx SUCCESS, socket %d used %d addresses assoc_id %d\n",
		       sd,
frtabu's avatar
frtabu committed
323 324 325
                       used_address,
                       assoc_id);
        }
326 327
    }

Konstantinos Alexandris's avatar
Konstantinos Alexandris committed
328 329 330 331
    ns = sctp_peeloff(sd, assoc_id);
    if (ns == -1) {
      perror("sctp_peeloff");
      printf("sctp_peeloff: sd=%d assoc_id=%d\n", sd, assoc_id);
332
      exit_fun("sctp_handle_new_association_req_multi fatal: sctp_peeloff error");
Konstantinos Alexandris's avatar
Konstantinos Alexandris committed
333
    }
334

frtabu's avatar
frtabu committed
335
    sctp_cnx = calloc(1, sizeof(*sctp_cnx));
336

frtabu's avatar
frtabu committed
337
    sctp_cnx->connection_type = connection_type;
338

frtabu's avatar
frtabu committed
339 340 341 342 343 344
    sctp_cnx->sd       = ns;
    sctp_cnx->task_id  = requestor;
    sctp_cnx->cnx_id   = sctp_new_association_req_p->ulp_cnx_id;
    sctp_cnx->ppid     = sctp_new_association_req_p->ppid;
    sctp_cnx->instance = instance;
    sctp_cnx->assoc_id = assoc_id;
345

frtabu's avatar
frtabu committed
346 347
    /* Add the socket to list of fd monitored by ITTI */
    itti_subscribe_event_fd(TASK_SCTP, ns);
348

frtabu's avatar
frtabu committed
349 350 351
    /* Insert new element at end of list */
    STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
    sctp_nb_cnx++;
352

frtabu's avatar
frtabu committed
353 354
    SCTP_DEBUG("Inserted new descriptor for sd %d in list, nb elements %u, assoc_id %d\n",
               ns, sctp_nb_cnx, assoc_id);
355 356
}

357
//------------------------------------------------------------------------------
laurent's avatar
laurent committed
358
static void
Lionel Gauthier's avatar
Lionel Gauthier committed
359
sctp_handle_new_association_req(
frtabu's avatar
frtabu committed
360 361 362
    const instance_t instance,
    const task_id_t requestor,
    const sctp_new_association_req_t * const sctp_new_association_req_p)
363
{
frtabu's avatar
frtabu committed
364 365 366
    int                           sd       = 0;
    int32_t                       assoc_id = 0;

Laurent's avatar
Laurent committed
367
    struct sctp_event_subscribe   events={0};
frtabu's avatar
frtabu committed
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384

    struct sctp_cnx_list_elm_s   *sctp_cnx = NULL;
    enum sctp_connection_type_e   connection_type = SCTP_TYPE_CLIENT;

    struct ifreq                  ifr;
    struct ifaddrs               *ifaddr = NULL;
    struct ifaddrs               *ifa    = NULL;
    int                           family = 0;
    int                           s = 0;
    struct in_addr                in;
    struct in6_addr               in6;
    /* Prepare a new SCTP association as requested by upper layer and try to connect
     * to remote host.
     */
    DevAssert(sctp_new_association_req_p != NULL);

    /* Create new socket with IPv6 affinity */
385
//#warning "SCTP may Force IPv4 only, here"
Lionel Gauthier's avatar
 
Lionel Gauthier committed
386
#ifdef NO_VIRTUAL_MACHINE
387

frtabu's avatar
frtabu committed
388 389 390 391 392
    // 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 (the working IPv4 address can be the last in the list...)
    if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
Lionel Gauthier's avatar
 
Lionel Gauthier committed
393
#else
394

frtabu's avatar
frtabu committed
395
    if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
396
#endif
frtabu's avatar
frtabu committed
397 398
        SCTP_ERROR("Socket creation failed: %s\n", strerror(errno));
        return;
399
    }
frtabu's avatar
frtabu committed
400 401 402 403 404 405 406 407 408 409 410

    /* Add the socket to list of fd monitored by ITTI */
    itti_subscribe_event_fd(TASK_SCTP, sd);

    if (sctp_set_init_opt(sd,
                          sctp_new_association_req_p->in_streams,
                          sctp_new_association_req_p->out_streams,
                          SCTP_MAX_ATTEMPTS, SCTP_TIMEOUT) != 0) {
        SCTP_ERROR("Setsockopt IPPROTO_SCTP_INITMSG failed: %s\n",
                   strerror(errno));
        itti_unsubscribe_event_fd(TASK_SCTP, sd);
411 412 413 414
        close(sd);
        return;
    }

frtabu's avatar
frtabu committed
415
    /* Subscribe to all events */
Raphael Defosseux's avatar
Raphael Defosseux committed
416 417 418 419 420 421 422
    events.sctp_data_io_event = 1;
    events.sctp_association_event = 1;
    events.sctp_address_event = 1;
    events.sctp_send_failure_event = 1;
    events.sctp_peer_error_event = 1;
    events.sctp_shutdown_event = 1;
    events.sctp_partial_delivery_event = 1;
frtabu's avatar
frtabu committed
423 424

    if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events,
425
                   8) < 0) {
frtabu's avatar
frtabu committed
426 427
        SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n",
                   strerror(errno));
428
        close(sd);
429
        return;
frtabu's avatar
frtabu committed
430
    }
431

frtabu's avatar
frtabu committed
432 433 434 435 436
    // Bind to device ... or we could bind to address also
    if (getifaddrs(&ifaddr) == -1) {
        SCTP_ERROR("getifaddrs failed: %s\n", strerror(errno));
        close(sd);
    }
437

frtabu's avatar
frtabu committed
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
    /* Walk through linked list, maintaining head pointer so we
       can free list later */
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == NULL)
            continue;

        family = ifa->ifa_addr->sa_family;

        /* For an AF_INET* interface address, display the address */
        if (sctp_new_association_req_p->local_address.ipv4 && family == AF_INET) {
            // compare address
            s = inet_aton(sctp_new_association_req_p->local_address.ipv4_address,
                          &in);

            if (s > 0 ) {
                if (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr == in.s_addr) {
Laurent THOMAS's avatar
Laurent THOMAS committed
454
                    struct sockaddr_in locaddr={0};
frtabu's avatar
frtabu committed
455
                    locaddr.sin_family = AF_INET;
456
                    locaddr.sin_port = 0;
frtabu's avatar
frtabu committed
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
                    locaddr.sin_addr.s_addr = in.s_addr;

                    if (sctp_bindx(sd, (struct sockaddr*)&locaddr, 1, SCTP_BINDX_ADD_ADDR) < 0) {
                        SCTP_ERROR("sctp_bindx SCTP_BINDX_ADD_ADDR failed: %s\n",
                                   strerror(errno));
                    } else {
                        SCTP_DEBUG("sctp_bindx SCTP_BINDX_ADD_ADDR socket bound to : %s\n",
                                   inet_ntoa(locaddr.sin_addr));
                    }
                    break;

                }
            }
        } else if (sctp_new_association_req_p->local_address.ipv6 && family == AF_INET6) {
            // compare address
            s = inet_pton(AF_INET6,
                          sctp_new_association_req_p->local_address.ipv6_address,
                          &in6);

            if (s == 1 ) {
                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), "%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));
                    } else {
                        SCTP_DEBUG("Setsockopt SOL_SOCKET socket bound to : %s\n",
                                   ifa->ifa_name);
                    }

                    break;
                }
            }
        }
494 495
    }

frtabu's avatar
frtabu committed
496 497 498 499 500 501
    freeifaddrs(ifaddr);

    /* Mark the socket as non-blocking */
    if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0) {
        SCTP_ERROR("fcntl F_SETFL O_NONBLOCK failed: %s\n",
                   strerror(errno));
502 503 504
        close(sd);
        return;
    }
frtabu's avatar
frtabu committed
505 506 507 508

    /* SOCK_STREAM socket type requires an explicit connect to the remote host
     * address and port.
     * Only use IPv4 for the first connection attempt
509
     */
frtabu's avatar
frtabu committed
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
    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 +
                                sctp_new_association_req_p->remote_address.ipv4;
        struct sockaddr_in addr[used_address];

        memset(addr, 0, used_address * sizeof(struct sockaddr_in));

        if (sctp_new_association_req_p->remote_address.ipv6 == 1) {
            if (inet_pton(AF_INET6, sctp_new_association_req_p->remote_address.ipv6_address,
                          &addr[address_index].sin_addr.s_addr) != 1) {
                SCTP_ERROR("Failed to convert ipv6 address %*s to network type\n",
                           (int)strlen(sctp_new_association_req_p->remote_address.ipv6_address),
                           sctp_new_association_req_p->remote_address.ipv6_address);
                close(sd);
                return;
            }

            SCTP_DEBUG("Converted ipv6 address %*s to network type\n",
                       (int)strlen(sctp_new_association_req_p->remote_address.ipv6_address),
                       sctp_new_association_req_p->remote_address.ipv6_address);

            addr[address_index].sin_family = AF_INET6;
            addr[address_index].sin_port   = htons(sctp_new_association_req_p->port);
            address_index++;
        }
537

frtabu's avatar
frtabu committed
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
        if (sctp_new_association_req_p->remote_address.ipv4 == 1) {
            if (inet_pton(AF_INET, sctp_new_association_req_p->remote_address.ipv4_address,
                          &addr[address_index].sin_addr.s_addr) != 1) {
                SCTP_ERROR("Failed to convert ipv4 address %*s to network type\n",
                           (int)strlen(sctp_new_association_req_p->remote_address.ipv4_address),
                           sctp_new_association_req_p->remote_address.ipv4_address);
                close(sd);
                return;
            }

            SCTP_DEBUG("Converted ipv4 address %*s to network type\n",
                       (int)strlen(sctp_new_association_req_p->remote_address.ipv4_address),
                       sctp_new_association_req_p->remote_address.ipv4_address);

            addr[address_index].sin_family = AF_INET;
            addr[address_index].sin_port   = htons(sctp_new_association_req_p->port);
            address_index++;
        }
556

frtabu's avatar
frtabu committed
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
        /* Connect to remote host and port */
        if (sctp_connectx(sd, (struct sockaddr *)addr, 1, &assoc_id) < 0) {
            /* sctp_connectx on non-blocking socket return EINPROGRESS */
            if (errno != EINPROGRESS) {
                SCTP_ERROR("Connect failed: %s\n", strerror(errno));
                sctp_itti_send_association_resp(
                    requestor, instance, -1, sctp_new_association_req_p->ulp_cnx_id,
                    SCTP_STATE_UNREACHABLE, 0, 0);
                /* Add the socket to list of fd monitored by ITTI */
                itti_unsubscribe_event_fd(TASK_SCTP, sd);
                close(sd);
                return;
            } else {
                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.
         * Connection will be accepted in the main event loop
         */
        struct sockaddr_in6 addr6;
583

frtabu's avatar
frtabu committed
584
        connection_type = SCTP_TYPE_SERVER;
585

frtabu's avatar
frtabu committed
586 587 588 589
        /* 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);
590
        addr6.sin6_flowinfo = 0;
591

frtabu's avatar
frtabu committed
592 593 594 595 596 597
        if (bind(sd, (struct sockaddr*)&addr6, sizeof(addr6)) < 0) {
            SCTP_ERROR("Failed to bind the socket to address any (v4/v6): %s\n",
                       strerror(errno));
            close(sd);
            return;
        }
598 599
    }

frtabu's avatar
frtabu committed
600
    sctp_cnx = calloc(1, sizeof(*sctp_cnx));
601

frtabu's avatar
frtabu committed
602
    sctp_cnx->connection_type = connection_type;
603

frtabu's avatar
frtabu committed
604 605 606 607 608 609
    sctp_cnx->sd       = sd;
    sctp_cnx->task_id  = requestor;
    sctp_cnx->cnx_id   = sctp_new_association_req_p->ulp_cnx_id;
    sctp_cnx->ppid     = sctp_new_association_req_p->ppid;
    sctp_cnx->instance = instance;
    sctp_cnx->assoc_id = assoc_id;
610

frtabu's avatar
frtabu committed
611 612 613
    /* Insert new element at end of list */
    STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
    sctp_nb_cnx++;
614

frtabu's avatar
frtabu committed
615 616
    SCTP_DEBUG("Inserted new descriptor for sd %d in list, nb elements %u, assoc_id %d\n",
               sd, sctp_nb_cnx, assoc_id);
617 618
}

frtabu's avatar
frtabu committed
619
//------------------------------------------------------------------------------
620
static void sctp_send_data(sctp_data_req_t *sctp_data_req_p)
621
{
frtabu's avatar
frtabu committed
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
    struct sctp_cnx_list_elm_s *sctp_cnx = NULL;

    DevAssert(sctp_data_req_p != NULL);
    DevAssert(sctp_data_req_p->buffer != NULL);
    DevAssert(sctp_data_req_p->buffer_length > 0);

    sctp_cnx = sctp_get_cnx(sctp_data_req_p->assoc_id, 0);

    if (sctp_cnx == NULL) {
        SCTP_ERROR("Failed to find SCTP description for assoc_id %d\n",
                   sctp_data_req_p->assoc_id);
        /* TODO: notify upper layer */
        return;
    }

    if (sctp_data_req_p->stream >= sctp_cnx->out_streams) {
        SCTP_ERROR("Requested stream (%"PRIu16") >= nb out streams (%"PRIu16")\n",
                   sctp_data_req_p->stream, sctp_cnx->out_streams);
        return;
    }

    /* Send message on specified stream of the sd association
     * NOTE: PPID should be defined in network order
     */
    if (sctp_sendmsg(sctp_cnx->sd, sctp_data_req_p->buffer,
                     sctp_data_req_p->buffer_length, NULL, 0,
                     htonl(sctp_cnx->ppid), 0, sctp_data_req_p->stream, 0, 0) < 0) {
        SCTP_ERROR("Sctp_sendmsg failed: %s\n", strerror(errno));
        /* TODO: notify upper layer */
        return;
    }
laurent's avatar
laurent committed
653
    free(sctp_data_req_p->buffer); // assuming it has been malloced
frtabu's avatar
frtabu committed
654 655 656
    SCTP_DEBUG("Successfully sent %u bytes on stream %d for assoc_id %u\n",
               sctp_data_req_p->buffer_length, sctp_data_req_p->stream,
               sctp_cnx->assoc_id);
657 658
}

659
//------------------------------------------------------------------------------
660
static int sctp_close_association(sctp_close_association_t *close_association_p)
661 662
{

frtabu's avatar
frtabu committed
663
    struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
664

frtabu's avatar
frtabu committed
665 666
    DevAssert(close_association_p != NULL);
    sctp_cnx = sctp_get_cnx(close_association_p->assoc_id, 0);
667

frtabu's avatar
frtabu committed
668 669 670 671 672 673 674 675 676 677 678 679 680
    if (sctp_cnx == NULL) {
        SCTP_ERROR("Failed to find SCTP description for assoc_id %d\n",
                   close_association_p->assoc_id);
        /* TODO: notify upper layer */
        return -1;
    } else {
        close(sctp_cnx->sd);
        STAILQ_REMOVE(&sctp_cnx_list, sctp_cnx, sctp_cnx_list_elm_s, entries);
        SCTP_DEBUG("Removed assoc_id %u (closed socket %u)\n",
                   sctp_cnx->assoc_id, (unsigned int)sctp_cnx->sd);
    }

    return 0;
681 682
}

683
//------------------------------------------------------------------------------
Lionel Gauthier's avatar
 
Lionel Gauthier committed
684
static int sctp_create_new_listener(
frtabu's avatar
frtabu committed
685 686 687 688
    const instance_t instance,
    const task_id_t  requestor,
    sctp_init_t     *init_p,
    int server_type)
Lionel Gauthier's avatar
 
Lionel Gauthier committed
689
{
Laurent THOMAS's avatar
Laurent THOMAS committed
690
    struct sctp_event_subscribe   event={0};
frtabu's avatar
frtabu committed
691 692 693 694 695 696 697 698 699 700 701 702 703
    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;
    }
Lionel Gauthier's avatar
 
Lionel Gauthier committed
704

frtabu's avatar
frtabu committed
705 706 707 708
    if ((used_addresses = init_p->nb_ipv4_addr + init_p->nb_ipv6_addr) == 0) {
        SCTP_WARN("No address provided...\n");
        return -1;
    }
Lionel Gauthier's avatar
 
Lionel Gauthier committed
709

frtabu's avatar
frtabu committed
710
    addr = calloc(used_addresses, sizeof(struct sockaddr));
Lionel Gauthier's avatar
 
Lionel Gauthier committed
711

frtabu's avatar
frtabu committed
712
    SCTP_DEBUG("Creating new listen socket on port %u with\n", init_p->port);
Lionel Gauthier's avatar
 
Lionel Gauthier committed
713

frtabu's avatar
frtabu committed
714 715
    if (init_p->ipv4 == 1) {
        struct sockaddr_in *ip4_addr;
Lionel Gauthier's avatar
 
Lionel Gauthier committed
716

frtabu's avatar
frtabu committed
717
        SCTP_DEBUG("ipv4 addresses:\n");
Lionel Gauthier's avatar
 
Lionel Gauthier committed
718

frtabu's avatar
frtabu committed
719
        for (i = 0; i < init_p->nb_ipv4_addr; i++) {
720
            SCTP_DEBUG("\t- "IPV4_ADDR"\n", IPV4_ADDR_FORMAT(init_p->ipv4_address[i]));
frtabu's avatar
frtabu committed
721 722 723 724 725
            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];
        }
Lionel Gauthier's avatar
 
Lionel Gauthier committed
726 727
    }

frtabu's avatar
frtabu committed
728 729
    if (init_p->ipv6 == 1) {
        struct sockaddr_in6 *ip6_addr;
Lionel Gauthier's avatar
 
Lionel Gauthier committed
730

frtabu's avatar
frtabu committed
731
        SCTP_DEBUG("ipv6 addresses:\n");
Lionel Gauthier's avatar
 
Lionel Gauthier committed
732

frtabu's avatar
frtabu committed
733 734 735 736 737
        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);
Lionel Gauthier's avatar
 
Lionel Gauthier committed
738

frtabu's avatar
frtabu committed
739 740 741 742 743 744
            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]);
            }
        }
Lionel Gauthier's avatar
 
Lionel Gauthier committed
745
    }
746

frtabu's avatar
frtabu committed
747
    if (server_type) {
Laurent Thomas's avatar
Laurent Thomas committed
748
        if ((sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0) {
frtabu's avatar
frtabu committed
749 750 751 752
            SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno);
            free(addr);
            return -1;
        }
753
    }
frtabu's avatar
frtabu committed
754 755 756 757 758 759
    else {
        if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
            SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno);
            free(addr);
            return -1;
        }
760
    }
Lionel Gauthier's avatar
 
Lionel Gauthier committed
761

762 763 764 765 766 767 768
    event.sctp_data_io_event = 1;
    event.sctp_association_event = 1;
    event.sctp_address_event = 1;
    event.sctp_send_failure_event = 1;
    event.sctp_peer_error_event = 1;
    event.sctp_shutdown_event = 1;
    event.sctp_partial_delivery_event = 1;
769

frtabu's avatar
frtabu committed
770
    if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &event,
771
                   8) < 0) {
frtabu's avatar
frtabu committed
772
        SCTP_ERROR("setsockopt: %s:%d\n", strerror(errno), errno);
773 774 775 776
        if (sd != -1) {
            close(sd);
            sd = -1;
        }
frtabu's avatar
frtabu committed
777 778 779
        free(addr);
        return -1;
    }
780

frtabu's avatar
frtabu committed
781
    sctp_cnx = calloc(1, sizeof(*sctp_cnx));
782

frtabu's avatar
frtabu committed
783 784 785 786 787 788
    if (server_type) {
        sctp_cnx->connection_type = SCTP_TYPE_MULTI_SERVER;
    }
    else {
        sctp_cnx->connection_type = SCTP_TYPE_SERVER;
    }
789

frtabu's avatar
frtabu committed
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
    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;
    }
806

frtabu's avatar
frtabu committed
807 808
    if (sctp_bindx(sd, addr, used_addresses, SCTP_BINDX_ADD_ADDR) != 0) {
        SCTP_ERROR("sctp_bindx: %s:%d\n", strerror(errno), errno);
809 810
        free(sctp_cnx);
        sctp_cnx = NULL;
frtabu's avatar
frtabu committed
811 812 813 814 815
        return -1;
    }

    if (listen(sd, 5) < 0) {
        SCTP_ERROR("listen: %s:%d\n", strerror(errno), errno);
816 817
        free(sctp_cnx);
        sctp_cnx = NULL;
frtabu's avatar
frtabu committed
818 819
        return -1;
    }
Laurent Thomas's avatar
Laurent Thomas committed
820
    SCTP_DEBUG("Created listen socket: %d\n", sd);
frtabu's avatar
frtabu committed
821 822 823
    /* Insert new element at end of list */
    STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
    sctp_nb_cnx++;
824

frtabu's avatar
frtabu committed
825 826
    /* Add the socket to list of fd monitored by ITTI */
    itti_subscribe_event_fd(TASK_SCTP, sd);
827

frtabu's avatar
frtabu committed
828
    return sd;
829
err:
830

frtabu's avatar
frtabu committed
831 832 833 834
    if (sd != -1) {
        close(sd);
        sd = -1;
    }
835

836 837 838 839 840
    if (sctp_cnx != NULL) {
        free(sctp_cnx);
        sctp_cnx = NULL;
    }

841 842 843 844 845
    if (addr != NULL) {
        free(addr);
        addr = NULL;
    }

frtabu's avatar
frtabu committed
846
    return -1;
847
}
848

849
//------------------------------------------------------------------------------
850 851 852
static inline
void
sctp_eNB_accept_associations(
frtabu's avatar
frtabu committed
853
    struct sctp_cnx_list_elm_s *sctp_cnx)
854
{
frtabu's avatar
frtabu committed
855
    int             client_sd;
856
    struct sockaddr_in6 saddr;
frtabu's avatar
frtabu committed
857
    socklen_t       saddr_size;
858

frtabu's avatar
frtabu committed
859
    DevAssert(sctp_cnx != NULL);
860

frtabu's avatar
frtabu committed
861
    saddr_size = sizeof(saddr);
862

frtabu's avatar
frtabu committed
863 864
    /* There is a new client connecting. Accept it...
     */
865
    if ((client_sd = accept(sctp_cnx->sd, (struct sockaddr*)&saddr, &saddr_size)) < 0) {
frtabu's avatar
frtabu committed
866 867 868 869
        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;
870

frtabu's avatar
frtabu committed
871
        /* This is an ipv6 socket */
872
        port = saddr.sin6_port;
873

frtabu's avatar
frtabu committed
874 875 876 877 878 879 880
        /* 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;
        }
881

frtabu's avatar
frtabu committed
882
        new_cnx = calloc(1, sizeof(*sctp_cnx));
883

frtabu's avatar
frtabu committed
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
        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;
        }
902

frtabu's avatar
frtabu committed
903 904 905 906 907 908
        /* 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);
909

frtabu's avatar
frtabu committed
910 911 912 913
        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);
    }
914 915
}

916
//------------------------------------------------------------------------------
Lionel Gauthier's avatar
Lionel Gauthier committed
917 918 919
static inline
void
sctp_eNB_read_from_socket(
frtabu's avatar
frtabu committed
920
    struct sctp_cnx_list_elm_s *sctp_cnx)
921
{
frtabu's avatar
frtabu committed
922
    DevAssert(sctp_cnx != NULL);
923

924 925 926
    int    flags = 0;
    struct sctp_sndrcvinfo sinfo={0};
    uint8_t buffer[SCTP_RECV_BUFFER_SIZE];
927

928 929
    int n = sctp_recvmsg(sctp_cnx->sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE,
                    NULL, NULL, 
frtabu's avatar
frtabu committed
930
                     &sinfo, &flags);
931

frtabu's avatar
frtabu committed
932
    if (n < 0) {
Haruki NAOI's avatar
Haruki NAOI committed
933 934
        if( (errno == ENOTCONN) || (errno == ECONNRESET) || (errno == ETIMEDOUT) || (errno == ECONNREFUSED) )
        {
frtabu's avatar
frtabu committed
935
            itti_unsubscribe_event_fd(TASK_SCTP, sctp_cnx->sd);
936

frtabu's avatar
frtabu committed
937
            SCTP_DEBUG("Received not connected for sd %d\n", sctp_cnx->sd);
Haruki NAOI's avatar
Haruki NAOI committed
938
            SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno);
939

frtabu's avatar
frtabu committed
940 941 942
            sctp_itti_send_association_resp(
                sctp_cnx->task_id, sctp_cnx->instance, -1,
                sctp_cnx->cnx_id, SCTP_STATE_UNREACHABLE, 0, 0);
943

frtabu's avatar
frtabu committed
944 945 946 947 948 949 950 951
            close(sctp_cnx->sd);
            STAILQ_REMOVE(&sctp_cnx_list, sctp_cnx, sctp_cnx_list_elm_s, entries);
            sctp_nb_cnx--;
            free(sctp_cnx);
        } else {
            SCTP_DEBUG("An error occured during read\n");
            SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno);
        }
952

frtabu's avatar
frtabu committed
953 954 955 956 957
        return;
    } else if (n == 0) {
        SCTP_DEBUG("return of sctp_recvmsg is 0...\n");
        return;
    }
958

959 960
    if (!(flags & MSG_EOR)) {
      SCTP_ERROR("fatal: partial SCTP messages are not handled\n");
961
      exit_fun("fatal: partial SCTP messages are not handled" );
962 963
    }

frtabu's avatar
frtabu committed
964 965 966
    if (flags & MSG_NOTIFICATION) {
        union sctp_notification *snp;
        snp = (union sctp_notification *)buffer;
967

frtabu's avatar
frtabu committed
968 969
        SCTP_DEBUG("Received notification for sd %d, type %u\n",
                   sctp_cnx->sd, snp->sn_header.sn_type);
970

frtabu's avatar
frtabu committed
971 972 973
        /* Client deconnection */
        if (SCTP_SHUTDOWN_EVENT == snp->sn_header.sn_type) {
            itti_unsubscribe_event_fd(TASK_SCTP, sctp_cnx->sd);
974

Laurent THOMAS's avatar
Laurent THOMAS committed
975
            SCTP_WARN("Received SCTP SHUTDOWN EVENT\n");
frtabu's avatar
frtabu committed
976
            close(sctp_cnx->sd);
977

frtabu's avatar
frtabu committed
978 979 980 981
            sctp_itti_send_association_resp(
                sctp_cnx->task_id, sctp_cnx->instance, sctp_cnx->assoc_id,
                sctp_cnx->cnx_id, SCTP_STATE_SHUTDOWN,
                0, 0);
982

frtabu's avatar
frtabu committed
983 984
            STAILQ_REMOVE(&sctp_cnx_list, sctp_cnx, sctp_cnx_list_elm_s, entries);
            sctp_nb_cnx--;
985

frtabu's avatar
frtabu committed
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
            free(sctp_cnx);
        }
        /* Association has changed. */
        else if (SCTP_ASSOC_CHANGE == snp->sn_header.sn_type) {
            struct sctp_assoc_change *sctp_assoc_changed;
            sctp_assoc_changed = &snp->sn_assoc_change;

            SCTP_DEBUG("Client association changed: %d\n", sctp_assoc_changed->sac_state);

            /* New physical association requested by a peer */
            switch (sctp_assoc_changed->sac_state) {
            case SCTP_COMM_UP: {
                if (sctp_get_peeraddresses(sctp_cnx->sd, NULL, NULL) != 0) {
                    /* TODO Failure -> notify upper layer */
                } else {
                    sctp_get_sockinfo(sctp_cnx->sd, &sctp_cnx->in_streams,
                                      &sctp_cnx->out_streams, &sctp_cnx->assoc_id);
                }

                SCTP_DEBUG("Comm up notified for sd %d, assigned assoc_id %d\n",
                           sctp_cnx->sd, sctp_cnx->assoc_id);

                sctp_itti_send_association_resp(
                    sctp_cnx->task_id, sctp_cnx->instance, sctp_cnx->assoc_id,
                    sctp_cnx->cnx_id, SCTP_STATE_ESTABLISHED,
                    sctp_cnx->out_streams, sctp_cnx->in_streams);

            }
            break;

            default:
Laurent THOMAS's avatar
Laurent THOMAS committed
1017 1018 1019 1020 1021 1022 1023 1024
                if ( sctp_assoc_changed->sac_state == SCTP_SHUTDOWN_COMP) 
                    SCTP_WARN("SCTP_ASSOC_CHANGE to SSCTP_SHUTDOWN_COMP\n");
                if ( sctp_assoc_changed->sac_state == SCTP_RESTART) 
                    SCTP_WARN("SCTP_ASSOC_CHANGE to SCTP_RESTART\n");
                if ( sctp_assoc_changed->sac_state == SCTP_CANT_STR_ASSOC) 
                    SCTP_ERROR("SCTP_ASSOC_CHANGE to SCTP_CANT_STR_ASSOC\n");
                if ( sctp_assoc_changed->sac_state == SCTP_COMM_LOST) 
                    SCTP_ERROR("SCTP_ASSOC_CHANGE to SCTP_COMM_LOST\n");
frtabu's avatar
frtabu committed
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
                break;
            }
        }
    } else {
        sctp_cnx->messages_recv++;

        if (ntohl(sinfo.sinfo_ppid) != sctp_cnx->ppid) {
            /* Mismatch in Payload Protocol Identifier,
             * may be we received unsollicited traffic from stack other than S1AP.
             */
            SCTP_ERROR("Received data from peer with unsollicited PPID %d, expecting %d\n",
                       ntohl(sinfo.sinfo_ppid),
                       sctp_cnx->ppid);
1038 1039
        }

1040 1041
        SCTP_DEBUG("[%d][%d] Msg of length %d received, on stream %d, PPID %d\n",
                   sinfo.sinfo_assoc_id, sctp_cnx->sd, n, 
frtabu's avatar
frtabu committed
1042
                   sinfo.sinfo_stream, ntohl(sinfo.sinfo_ppid));
1043

frtabu's avatar
frtabu committed
1044
        sctp_itti_send_new_message_ind(sctp_cnx->task_id,
1045
                                       sctp_cnx->instance,
frtabu's avatar
frtabu committed
1046
                                       sinfo.sinfo_assoc_id,
1047 1048 1049
                                       buffer,
                                       n,
                                       sinfo.sinfo_stream);
1050
    }
1051 1052
}

1053
//------------------------------------------------------------------------------
Lionel Gauthier's avatar
Lionel Gauthier committed
1054
void
laurent's avatar
laurent committed
1055
static sctp_eNB_flush_sockets(
frtabu's avatar
frtabu committed
1056
    struct epoll_event *events, int nb_events)
1057
{
frtabu's avatar
frtabu committed
1058 1059
    int i;
    struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
1060

frtabu's avatar
frtabu committed
1061 1062
    for (i = 0; i < nb_events; i++) {
        sctp_cnx = sctp_get_cnx(-1, events[i].data.fd);
1063

frtabu's avatar
frtabu committed
1064 1065 1066
        if (sctp_cnx == NULL) {
            continue;
        }
1067

frtabu's avatar
frtabu committed
1068
        SCTP_DEBUG("Found data for descriptor %d\n", events[i].data.fd);
1069

frtabu's avatar
frtabu committed
1070 1071 1072 1073 1074 1075 1076 1077 1078
        if (sctp_cnx->connection_type == SCTP_TYPE_CLIENT) {
            sctp_eNB_read_from_socket(sctp_cnx);
        }
        else if (sctp_cnx->connection_type == SCTP_TYPE_MULTI_SERVER) {
            sctp_eNB_accept_associations_multi(sctp_cnx);
        }
        else {
            sctp_eNB_accept_associations(sctp_cnx);
        }
1079 1080 1081
    }
}

1082
//------------------------------------------------------------------------------
laurent's avatar
laurent committed
1083
static void sctp_eNB_init(void)
1084
{
frtabu's avatar
frtabu committed
1085
    SCTP_DEBUG("Starting SCTP layer\n");
1086

frtabu's avatar
frtabu committed
1087
    STAILQ_INIT(&sctp_cnx_list);
1088

frtabu's avatar
frtabu committed
1089
    itti_mark_task_ready(TASK_SCTP);
laurent's avatar
laurent committed
1090
}
1091

laurent's avatar
laurent committed
1092
//------------------------------------------------------------------------------
laurent's avatar
laurent committed
1093
static void sctp_eNB_process_itti_msg()
laurent's avatar
laurent committed
1094 1095 1096 1097
{
    int                 nb_events;
    MessageDef         *received_msg = NULL;
    int                 result;
1098

1099
    itti_receive_msg(TASK_SCTP, &received_msg);
1100

1101 1102
    /* Check if there is a packet to handle */
    if (received_msg != NULL) {
Laurent Thomas's avatar
Laurent Thomas committed
1103 1104
      LOG_D(SCTP,"Received message %d:%s\n",
		 ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
frtabu's avatar
frtabu committed
1105 1106 1107
        switch (ITTI_MSG_ID(received_msg)) {
        case SCTP_INIT_MSG: {
            if (sctp_create_new_listener(
1108
                        ITTI_MSG_DESTINATION_INSTANCE(received_msg),
frtabu's avatar
frtabu committed
1109 1110 1111 1112 1113
                        ITTI_MSG_ORIGIN_ID(received_msg),
                        &received_msg->ittiMsg.sctp_init,0) < 0) {
                /* SCTP socket creation or bind failed... */
                SCTP_ERROR("Failed to create new SCTP listener\n");
            }
1114
        }
frtabu's avatar
frtabu committed
1115 1116 1117
        break;

        case SCTP_INIT_MSG_MULTI_REQ: {
Laurent Thomas's avatar
Laurent Thomas committed
1118
           int multi_sd = sctp_create_new_listener(
1119
                           ITTI_MSG_DESTINATION_INSTANCE(received_msg),
frtabu's avatar
frtabu committed
1120 1121 1122 1123 1124 1125 1126 1127
                           ITTI_MSG_ORIGIN_ID(received_msg),
                           &received_msg->ittiMsg.sctp_init_multi,1);
            /* We received a new connection request */
            if (multi_sd < 0) {
                /* SCTP socket creation or bind failed... */
                SCTP_ERROR("Failed to create new SCTP listener\n");
            }
            sctp_itti_send_init_msg_multi_cnf(
1128
                ITTI_MSG_ORIGIN_ID(received_msg),
1129
                ITTI_MSG_DESTINATION_INSTANCE(received_msg),
1130
                multi_sd);
frtabu's avatar
frtabu committed
1131
        }
1132 1133
        break;

frtabu's avatar
frtabu committed
1134
        case SCTP_NEW_ASSOCIATION_REQ: {
1135
            sctp_handle_new_association_req(ITTI_MSG_DESTINATION_INSTANCE(received_msg),
frtabu's avatar
frtabu committed
1136 1137 1138
                                            ITTI_MSG_ORIGIN_ID(received_msg),
                                            &received_msg->ittiMsg.sctp_new_association_req);
        }
1139 1140
        break;

frtabu's avatar
frtabu committed
1141
        case SCTP_NEW_ASSOCIATION_REQ_MULTI: {
1142
            sctp_handle_new_association_req_multi(ITTI_MSG_DESTINATION_INSTANCE(received_msg),
frtabu's avatar
frtabu committed
1143 1144 1145 1146
                                                  ITTI_MSG_ORIGIN_ID(received_msg),
                                                  &received_msg->ittiMsg.sctp_new_association_req_multi);
        }
        break;
1147

frtabu's avatar
frtabu committed
1148
        case SCTP_CLOSE_ASSOCIATION:
1149 1150
          sctp_close_association(&received_msg->ittiMsg.sctp_close_association);
          break;
frtabu's avatar
frtabu committed
1151 1152 1153 1154 1155 1156 1157

        case TERMINATE_MESSAGE:
            SCTP_WARN("*** Exiting SCTP thread\n");
            itti_exit_task();
            break;

        case SCTP_DATA_REQ: {
1158
          sctp_send_data(&received_msg->ittiMsg.sctp_data_req);
frtabu's avatar
frtabu committed
1159
        }
1160 1161
        break;

frtabu's avatar
frtabu committed
1162 1163 1164 1165 1166 1167 1168 1169 1170
        default:
            SCTP_ERROR("Received unhandled message %d:%s\n",
                       ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
            break;
        }

        result = itti_free(ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
        received_msg = NULL;
1171
    }
laurent's avatar
laurent committed
1172 1173
    struct epoll_event events[20];
    nb_events = itti_get_events(TASK_SCTP, events, 20);
1174 1175
    /* Now handle notifications for other sockets */
    sctp_eNB_flush_sockets(events, nb_events);
laurent's avatar
laurent committed
1176

laurent's avatar
laurent committed
1177
    return;
laurent's avatar
laurent committed
1178
}
1179

laurent's avatar
laurent committed
1180 1181 1182
//------------------------------------------------------------------------------
void *sctp_eNB_task(void *arg)
{
frtabu's avatar
frtabu committed
1183
    sctp_eNB_init();
laurent's avatar
laurent committed
1184

frtabu's avatar
frtabu committed
1185
    while (1) {
laurent's avatar
laurent committed
1186
        sctp_eNB_process_itti_msg();
frtabu's avatar
frtabu committed
1187
    }
1188

frtabu's avatar
frtabu committed
1189
    return NULL;
1190
}