sctp_eNB_task.c 37.6 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
Cedric Roux's avatar
Cedric Roux committed
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>
gauthier's avatar
gauthier committed
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
43
44
45
46

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

#include <arpa/inet.h>

#include "assertions.h"
#include "queue.h"

#include "intertask_interface.h"

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

gauthier's avatar
   
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 {
62
63
  SCTP_TYPE_CLIENT,
  SCTP_TYPE_SERVER,
64
  SCTP_TYPE_MULTI_SERVER,
65
  SCTP_TYPE_MAX
66
67
};

gauthier's avatar
   
gauthier committed
68
typedef struct sctp_cnx_list_elm_s {
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
gauthier's avatar
   
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
98
struct sctp_cnx_list_elm_s *sctp_get_cnx(int32_t assoc_id, int sd)
{
  struct sctp_cnx_list_elm_s *elm;
99

100
101
102
103
104
105
106
107
108
  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;
      }
109
    }
110
  }
111

112
  return NULL;
113
114
}

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
//------------------------------------------------------------------------------
static inline
void
sctp_eNB_accept_associations_multi(
  struct sctp_cnx_list_elm_s *sctp_cnx)
{
  int                    ns;
  int                    n;
  int                    flags = 0;
  socklen_t              from_len;
  struct sctp_sndrcvinfo sinfo;

  struct sockaddr_in addr;
  uint8_t buffer[SCTP_RECV_BUFFER_SIZE];

  DevAssert(sctp_cnx != NULL);

  memset((void *)&addr, 0, sizeof(struct sockaddr_in));
  from_len = (socklen_t)sizeof(struct sockaddr_in);
  memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));

  n = sctp_recvmsg(sctp_cnx->sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE,
                   (struct sockaddr *)&addr, &from_len,
                   &sinfo, &flags);

  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;
  }

  if (flags & MSG_NOTIFICATION) {
    union sctp_notification *snp;
    snp = (union sctp_notification *)buffer;

    SCTP_DEBUG("Received notification for sd %d, type %u\n",
               sctp_cnx->sd, snp->sn_header.sn_type);

    /* 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;

      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: {
        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;

          new_cnx = calloc(1, sizeof(*sctp_cnx));

	  DevAssert(new_cnx != NULL);

	  new_cnx->connection_type = SCTP_TYPE_CLIENT;

          ns = sctp_peeloff(sctp_cnx->sd, sctp_assoc_changed->sac_assoc_id);

	  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;

          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;
          }

	  /* 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, ns);

	  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;

      default:
        break;
      }
    }
  } else {
       SCTP_DEBUG("No notification from SCTP\n");
  }
}

//------------------------------------------------------------------------------
void
sctp_handle_new_association_req_multi(
  const instance_t instance,
  const task_id_t requestor,
223
  const sctp_new_association_req_multi_t * const sctp_new_association_req_p)
224
225
{
  int                           ns;
226
  int sd;
227
228
229
230
231
232
233
234
235
236
237

  int32_t                       assoc_id = 0;

  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.
   */
  DevAssert(sctp_new_association_req_p != NULL);

238
239
  sd = sctp_new_association_req_p->multi_sd;

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  /* Create new socket with IPv6 affinity */
//#warning "SCTP may Force IPv4 only, here"

  /* 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));
    //close(sd);
    //return;
  //}

  /* 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);
270
271
272
        //close(sd);
        //return;
        exit(1);
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
      }

      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++;
    }

    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);
290
291
292
        //close(sd);
        //return;
        exit(1);
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
      }

      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);
314
        //close(sd);
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
        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);
    }
  }

  ns = sctp_peeloff(sd,assoc_id);

  sctp_cnx = calloc(1, sizeof(*sctp_cnx));

  sctp_cnx->connection_type = connection_type;

  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;

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

  /* Insert new element at end of list */
  STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
  sctp_nb_cnx++;

  SCTP_DEBUG("Inserted new descriptor for sd %d in list, nb elements %u, assoc_id %d\n",
             ns, sctp_nb_cnx, assoc_id);
}

351
//------------------------------------------------------------------------------
gauthier's avatar
gauthier committed
352
353
void
sctp_handle_new_association_req(
354
355
356
  const instance_t instance,
  const task_id_t requestor,
  const sctp_new_association_req_t * const sctp_new_association_req_p)
357
{
358
  int                           sd       = 0;
359
  int32_t                       assoc_id = 0;
360

361
  struct sctp_event_subscribe   events;
362

363
364
  struct sctp_cnx_list_elm_s   *sctp_cnx = NULL;
  enum sctp_connection_type_e   connection_type = SCTP_TYPE_CLIENT;
365

366
  struct ifreq                  ifr;
367
368
369
370
  struct ifaddrs               *ifaddr = NULL;
  struct ifaddrs               *ifa    = NULL;
  int                           family = 0;
  int                           s = 0;
371
372
373
374
375
376
  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);
377

378
  /* Create new socket with IPv6 affinity */
379
//#warning "SCTP may Force IPv4 only, here"
gauthier's avatar
   
gauthier committed
380
#ifdef NO_VIRTUAL_MACHINE
381
382
383
384

  // 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
gauthier's avatar
typo    
gauthier committed
385
  // with AF_INET (the working IPv4 address can be the last in the list...)
386
  if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
gauthier's avatar
   
gauthier committed
387
#else
388

389
390
391
392
393
394
395
396
397
  if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
#endif
    SCTP_ERROR("Socket creation failed: %s\n", strerror(errno));
    return;
  }

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

398
399
400
401
  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) {
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    SCTP_ERROR("Setsockopt IPPROTO_SCTP_INITMSG failed: %s\n",
               strerror(errno));
    itti_unsubscribe_event_fd(TASK_SCTP, sd);
    close(sd);
    return;
  }

  /* Subscribe to all events */
  memset((void *)&events, 1, sizeof(struct sctp_event_subscribe));

  if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events,
                 sizeof(struct sctp_event_subscribe)) < 0) {
    SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n",
               strerror(errno));
    close(sd);
    return;
  }

  // Bind to device ... or we could bind to address also
  if (getifaddrs(&ifaddr) == -1) {
    SCTP_ERROR("getifaddrs failed: %s\n", strerror(errno));
    close(sd);
  }

  /* 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);
439

440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
      if (s > 0 ) {
        if (((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr == in.s_addr) {
          struct sockaddr_in locaddr;
          locaddr.sin_family = AF_INET;
          locaddr.sin_port = htons(sctp_new_association_req_p->port);
          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;
thomasl's avatar
thomasl committed
455

456
457
458
459
460
        }
      }
    } else if (sctp_new_association_req_p->local_address.ipv6 && family == AF_INET6) {
      // compare address
      s = inet_pton(AF_INET6,
gauthier's avatar
gauthier committed
461
462
                    sctp_new_association_req_p->local_address.ipv6_address,
                    &in6);
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

      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;
gauthier's avatar
gauthier committed
479
        }
480
      }
gauthier's avatar
gauthier committed
481
    }
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  }

  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));
    close(sd);
    return;
  }

  /* 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;
      }
gauthier's avatar
gauthier committed
516

517
518
519
      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);
gauthier's avatar
gauthier committed
520

521
522
523
524
525
526
527
528
529
530
531
      addr[address_index].sin_family = AF_INET6;
      addr[address_index].sin_port   = htons(sctp_new_association_req_p->port);
      address_index++;
    }

    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);
532
        close(sd);
533
        return;
534
      }
535

536
537
538
      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);
539

540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
      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);
      }
561
    } else {
562
563
564
565
566
567
568
569
570
      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;
571

572
    connection_type = SCTP_TYPE_SERVER;
573

574
575
576
577
    /* 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);
578

579
580
581
582
583
    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;
584
    }
585
  }
586

587
  sctp_cnx = calloc(1, sizeof(*sctp_cnx));
588

589
  sctp_cnx->connection_type = connection_type;
590

591
592
593
594
595
596
  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;
597

598
599
600
  /* Insert new element at end of list */
  STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
  sctp_nb_cnx++;
601

602
603
  SCTP_DEBUG("Inserted new descriptor for sd %d in list, nb elements %u, assoc_id %d\n",
             sd, sctp_nb_cnx, assoc_id);
604
605
}

606
  //------------------------------------------------------------------------------
gauthier's avatar
   
gauthier committed
607
void sctp_send_data(
608
609
610
  instance_t       instance,
  task_id_t        task_id,
  sctp_data_req_t *sctp_data_req_p)
611
{
612
613
614
615
616
617
618
619
620
621
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
  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;
  }

  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);
647
648
}

649
//------------------------------------------------------------------------------
gauthier's avatar
gauthier committed
650
static int sctp_close_association(
651
652
653
  const instance_t instance,
  const task_id_t  requestor,
  sctp_close_association_t     *close_association_p)
gauthier's avatar
gauthier committed
654
655
{

656
  struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
gauthier's avatar
gauthier committed
657

658
659
  DevAssert(close_association_p != NULL);
  sctp_cnx = sctp_get_cnx(close_association_p->assoc_id, 0);
gauthier's avatar
gauthier committed
660

661
662
663
664
665
666
667
668
669
670
671
672
673
  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, sctp_cnx->sd);
  }

  return 0;
gauthier's avatar
gauthier committed
674
675
}

676
//------------------------------------------------------------------------------
gauthier's avatar
   
gauthier committed
677
static int sctp_create_new_listener(
678
679
  const instance_t instance,
  const task_id_t  requestor,
680
681
  sctp_init_t     *init_p,
  int server_type)
gauthier's avatar
   
gauthier committed
682
{
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  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;
  }
gauthier's avatar
   
gauthier committed
697

698
699
700
701
  if ((used_addresses = init_p->nb_ipv4_addr + init_p->nb_ipv6_addr) == 0) {
    SCTP_WARN("No address provided...\n");
    return -1;
  }
gauthier's avatar
   
gauthier committed
702

703
  addr = calloc(used_addresses, sizeof(struct sockaddr));
gauthier's avatar
   
gauthier committed
704

705
  SCTP_DEBUG("Creating new listen socket on port %u with\n", init_p->port);
gauthier's avatar
   
gauthier committed
706

707
708
  if (init_p->ipv4 == 1) {
    struct sockaddr_in *ip4_addr;
gauthier's avatar
   
gauthier committed
709

710
    SCTP_DEBUG("ipv4 addresses:\n");
gauthier's avatar
   
gauthier committed
711

712
713
714
715
716
717
718
    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];
gauthier's avatar
   
gauthier committed
719
    }
720
  }
gauthier's avatar
   
gauthier committed
721

722
723
  if (init_p->ipv6 == 1) {
    struct sockaddr_in6 *ip6_addr;
gauthier's avatar
   
gauthier committed
724

725
    SCTP_DEBUG("ipv6 addresses:\n");
gauthier's avatar
   
gauthier committed
726

727
728
729
730
731
    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);
gauthier's avatar
   
gauthier committed
732

733
734
735
736
737
      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]);
      }
gauthier's avatar
   
gauthier committed
738
    }
739
740
  }

741
742
743
744
745
746
747
748
749
750
751
  if (server_type) {
    if ((sd = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0) {
      SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno);
      return -1;
    }
  }
  else {
    if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
      SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno);
      return -1;
    }
752
  }
gauthier's avatar
   
gauthier committed
753

754
  memset((void *)&event, 1, sizeof(struct sctp_event_subscribe));
755

756
757
758
759
760
761
762
763
  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));

764
765
766
767
768
769
770
  if (server_type) {
    sctp_cnx->connection_type = SCTP_TYPE_MULTI_SERVER;
  }
  else {
    sctp_cnx->connection_type = SCTP_TYPE_SERVER;
  }

771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
  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;
  }
792

793
794
795
796
  if (listen(sd, 5) < 0) {
    SCTP_ERROR("listen: %s:%d\n", strerror(errno), errno);
    return -1;
  }
797

798
799
800
  /* Insert new element at end of list */
  STAILQ_INSERT_TAIL(&sctp_cnx_list, sctp_cnx, entries);
  sctp_nb_cnx++;
801

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

805
806
  return sd;
err:
807

808
809
810
811
  if (sd != -1) {
    close(sd);
    sd = -1;
  }
812

813
814
  return -1;
}
815

816
//------------------------------------------------------------------------------
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
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;
    }
848

849
    new_cnx = calloc(1, sizeof(*sctp_cnx));
850

851
    DevAssert(new_cnx != NULL);
852

853
    new_cnx->connection_type = SCTP_TYPE_CLIENT;
854

855
856
857
858
859
860
    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;
861

862
863
864
865
866
867
    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;
868
    }
869
870
871
872
873
874
875
876
877
878
879
880

    /* 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);
  }
881
882
}

883
//------------------------------------------------------------------------------
gauthier's avatar
gauthier committed
884
885
886
static inline
void
sctp_eNB_read_from_socket(
887
  struct sctp_cnx_list_elm_s *sctp_cnx)
888
{
889
890
891
  int                    flags = 0, n;
  socklen_t              from_len;
  struct sctp_sndrcvinfo sinfo;
892

893
894
  struct sockaddr_in addr;
  uint8_t buffer[SCTP_RECV_BUFFER_SIZE];
895

896
  DevAssert(sctp_cnx != NULL);
897

898
899
900
  memset((void *)&addr, 0, sizeof(struct sockaddr_in));
  from_len = (socklen_t)sizeof(struct sockaddr_in);
  memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
901

902
903
904
  n = sctp_recvmsg(sctp_cnx->sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE,
                   (struct sockaddr *)&addr, &from_len,
                   &sinfo, &flags);
905

906
907
908
  if (n < 0) {
    if (errno == ENOTCONN) {
      itti_unsubscribe_event_fd(TASK_SCTP, sctp_cnx->sd);
909

910
      SCTP_DEBUG("Received not connected for sd %d\n", sctp_cnx->sd);
911

912
913
914
915
916
917
918
919
920
921
922
      sctp_itti_send_association_resp(
        sctp_cnx->task_id, sctp_cnx->instance, -1,
        sctp_cnx->cnx_id, SCTP_STATE_UNREACHABLE, 0, 0);

      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);
923
924
    }

925
926
927
928
929
    return;
  } else if (n == 0) {
    SCTP_DEBUG("return of sctp_recvmsg is 0...\n");
    return;
  }
930

931
932
933
  if (flags & MSG_NOTIFICATION) {
    union sctp_notification *snp;
    snp = (union sctp_notification *)buffer;
934

935
936
    SCTP_DEBUG("Received notification for sd %d, type %u\n",
               sctp_cnx->sd, snp->sn_header.sn_type);
937

938
939
940
    /* Client deconnection */
    if (SCTP_SHUTDOWN_EVENT == snp->sn_header.sn_type) {
      itti_unsubscribe_event_fd(TASK_SCTP, sctp_cnx->sd);
941

942
      close(sctp_cnx->sd);
943

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
      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);

      STAILQ_REMOVE(&sctp_cnx_list, sctp_cnx, sctp_cnx_list_elm_s, entries);
      sctp_nb_cnx--;

      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);
969
970
        }

971
972
973
974
975
976
977
978
979
980
        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;
981

982
      default:
983
        SCTP_WARN("unhandled: SCTP_ASSOC_CHANGE to %d\n", sctp_assoc_changed->sac_state);
984
985
        break;
      }
986
    }
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
  } 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);
    }

    SCTP_DEBUG("[%d][%d] Msg of length %d received from port %u, on stream %d, PPID %d\n",
               sinfo.sinfo_assoc_id, sctp_cnx->sd, n, ntohs(addr.sin_port),
               sinfo.sinfo_stream, ntohl(sinfo.sinfo_ppid));

    sctp_itti_send_new_message_ind(sctp_cnx->task_id,
                                   sinfo.sinfo_assoc_id,
                                   buffer, n, sinfo.sinfo_stream);
  }
1007
1008
}

1009
//------------------------------------------------------------------------------
gauthier's avatar
gauthier committed
1010
1011
void
sctp_eNB_flush_sockets(
1012
  struct epoll_event *events, int nb_events)
1013
{
1014
1015
  int i;
  struct sctp_cnx_list_elm_s *sctp_cnx = NULL;
1016

1017
1018
1019
1020
1021
1022
1023
1024
1025
  if (events == NULL) {
    return;
  }

  for (i = 0; i < nb_events; i++) {
    sctp_cnx = sctp_get_cnx(-1, events[i].data.fd);

    if (sctp_cnx == NULL) {
      continue;
1026
1027
    }

1028
1029
1030
1031
    SCTP_DEBUG("Found data for descriptor %d\n", events[i].data.fd);

    if (sctp_cnx->connection_type == SCTP_TYPE_CLIENT) {
      sctp_eNB_read_from_socket(sctp_cnx);
1032
1033
1034
1035
1036
    }
    else if (sctp_cnx->connection_type == SCTP_TYPE_MULTI_SERVER) {
      sctp_eNB_accept_associations_multi(sctp_cnx);
    }
    else {
1037
      sctp_eNB_accept_associations(sctp_cnx);
1038
    }
1039
  }
1040
1041
}

1042
//------------------------------------------------------------------------------
Thomas Laurent's avatar
Thomas Laurent committed
1043
void sctp_eNB_init(void)
1044
{
1045
1046
1047
1048
1049
  SCTP_DEBUG("Starting SCTP layer\n");

  STAILQ_INIT(&sctp_cnx_list);

  itti_mark_task_ready(TASK_SCTP);
1050
  MSC_START_USE();
1051

Thomas Laurent's avatar
Thomas Laurent committed
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
}
 
//------------------------------------------------------------------------------
void *sctp_eNB_process_itti_msg(void *notUsed)
{
    int                 nb_events;
    struct epoll_event *events;
    MessageDef         *received_msg = NULL;
    int                 result;
    
1062
    itti_receive_msg(TASK_SCTP, &received_msg);
1063

1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
    /* Check if there is a packet to handle */
    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),
1074
              &received_msg->ittiMsg.sctp_init,0) < 0) {
1075
1076
1077
1078
1079
1080
          /* SCTP socket creation or bind failed... */
          SCTP_ERROR("Failed to create new SCTP listener\n");
        }
      }
      break;

1081
1082
1083
1084
      case SCTP_INIT_MSG_MULTI_REQ: {
        int multi_sd;

        SCTP_DEBUG("Received SCTP_INIT_MSG_MULTI_REQ\n");
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094

        multi_sd = sctp_create_new_listener(
              ITTI_MESSAGE_GET_INSTANCE(received_msg),
              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");
        }
1095
1096
1097
1098
        sctp_itti_send_init_msg_multi_cnf(
                ITTI_MSG_ORIGIN_ID(received_msg),
                ITTI_MESSAGE_GET_INSTANCE(received_msg),
                multi_sd);
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
      }
      break;

      case SCTP_NEW_ASSOCIATION_REQ: {
        sctp_handle_new_association_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                        ITTI_MSG_ORIGIN_ID(received_msg),
                                        &received_msg->ittiMsg.sctp_new_association_req);
      }
      break;

      case SCTP_NEW_ASSOCIATION_REQ_MULTI: {
        sctp_handle_new_association_req_multi(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                        ITTI_MSG_ORIGIN_ID(received_msg),
1112
                                        &received_msg->ittiMsg.sctp_new_association_req_multi);
1113
1114
1115
      }
      break;

1116
1117
1118
1119
1120
1121
1122
      case SCTP_CLOSE_ASSOCIATION:
        sctp_close_association(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                               ITTI_MSG_ORIGIN_ID(received_msg),
                               &received_msg->ittiMsg.sctp_close_association);
        break;

      case TERMINATE_MESSAGE:
1123
        SCTP_WARN("*** Exiting SCTP thread\n");
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
        itti_exit_task();
        break;

      case SCTP_DATA_REQ: {
        sctp_send_data(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                       ITTI_MSG_ORIGIN_ID(received_msg),
                       &received_msg->ittiMsg.sctp_data_req);
      }
      break;

      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;
1143
    }
1144
1145
1146
1147

    nb_events = itti_get_events(TASK_SCTP, &events);
    /* Now handle notifications for other sockets */
    sctp_eNB_flush_sockets(events, nb_events);
Thomas Laurent's avatar
Thomas Laurent committed
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158

    return NULL;
}
 
//------------------------------------------------------------------------------
void *sctp_eNB_task(void *arg)
{
  sctp_eNB_init();

  while (1) {
    (void) sctp_eNB_process_itti_msg(NULL);
1159
1160
1161
  }

  return NULL;
1162
}