2017-10-18 16:09:06 +00:00
|
|
|
#define TRACE_MODULE _s1ap_usrsctp
|
|
|
|
|
|
|
|
#include "core_debug.h"
|
|
|
|
#include "core_thread.h"
|
2017-11-22 15:19:28 +00:00
|
|
|
#include "core_net.h"
|
2017-10-18 16:09:06 +00:00
|
|
|
|
|
|
|
#include "mme_event.h"
|
|
|
|
|
|
|
|
#include "s1ap_path.h"
|
|
|
|
|
|
|
|
#if HAVE_USRSCTP_H
|
2017-10-19 03:50:39 +00:00
|
|
|
#ifndef INET
|
|
|
|
#define INET 1
|
|
|
|
#endif
|
|
|
|
#ifndef INET6
|
|
|
|
#define INET6 1
|
|
|
|
#endif
|
2017-10-18 16:09:06 +00:00
|
|
|
#include <usrsctp.h>
|
|
|
|
#endif
|
|
|
|
|
2017-10-19 03:50:39 +00:00
|
|
|
#define LOCAL_UDP_PORT 9899
|
2017-10-18 16:09:06 +00:00
|
|
|
|
2017-10-20 04:18:58 +00:00
|
|
|
static void handle_notification(union sctp_notification *notif, size_t n);
|
2017-10-18 16:09:06 +00:00
|
|
|
static int s1ap_usrsctp_recv_cb(struct socket *sock,
|
|
|
|
union sctp_sockstore addr, void *data, size_t datalen,
|
|
|
|
struct sctp_rcvinfo rcv, int flags, void *ulp_info);
|
|
|
|
|
|
|
|
static void debug_printf(const char *format, ...);
|
|
|
|
|
2017-10-20 04:18:58 +00:00
|
|
|
int accept_thread_should_stop = 0;
|
|
|
|
static thread_id accept_thread;
|
|
|
|
static void *THREAD_FUNC accept_main(thread_id id, void *data);
|
|
|
|
|
2017-10-18 16:09:06 +00:00
|
|
|
status_t s1ap_open(void)
|
|
|
|
{
|
2017-10-20 04:18:58 +00:00
|
|
|
status_t rv;
|
2017-10-18 16:09:06 +00:00
|
|
|
char buf[INET_ADDRSTRLEN];
|
|
|
|
|
|
|
|
struct socket *psock = NULL;
|
|
|
|
struct sockaddr_in local_addr;
|
2017-10-19 04:42:07 +00:00
|
|
|
const int on = 1;
|
|
|
|
struct sctp_event event;
|
|
|
|
c_uint16_t event_types[] = {
|
2017-10-19 03:50:39 +00:00
|
|
|
SCTP_ASSOC_CHANGE,
|
|
|
|
SCTP_PEER_ADDR_CHANGE,
|
|
|
|
SCTP_REMOTE_ERROR,
|
|
|
|
SCTP_SHUTDOWN_EVENT,
|
|
|
|
SCTP_ADAPTATION_INDICATION,
|
|
|
|
SCTP_PARTIAL_DELIVERY_EVENT
|
|
|
|
};
|
2017-10-19 04:42:07 +00:00
|
|
|
int i;
|
2017-10-18 16:09:06 +00:00
|
|
|
|
|
|
|
usrsctp_init(LOCAL_UDP_PORT, NULL, debug_printf);
|
|
|
|
#ifdef SCTP_DEBUG
|
|
|
|
usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
|
|
|
|
#endif
|
|
|
|
usrsctp_sysctl_set_sctp_blackhole(2);
|
|
|
|
usrsctp_sysctl_set_sctp_enable_sack_immediately(1);
|
|
|
|
|
|
|
|
if (!(psock = usrsctp_socket(
|
|
|
|
AF_INET, SOCK_STREAM, IPPROTO_SCTP, s1ap_usrsctp_recv_cb,
|
|
|
|
NULL, 0, NULL)))
|
|
|
|
{
|
|
|
|
d_error("usrsctp_socket failed");
|
|
|
|
return CORE_ERROR;
|
|
|
|
}
|
|
|
|
|
2017-11-22 12:50:08 +00:00
|
|
|
mme_self()->s1ap_sock = (sock_id)psock;
|
2017-10-18 16:09:06 +00:00
|
|
|
|
2017-10-19 04:42:07 +00:00
|
|
|
if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_RECVRCVINFO,
|
2017-10-19 03:50:39 +00:00
|
|
|
&on, sizeof(int)) < 0)
|
|
|
|
{
|
2017-10-20 04:18:58 +00:00
|
|
|
d_error("usrsctp_setsockopt SCTP_RECVRCVINFO failed");
|
2017-10-19 03:50:39 +00:00
|
|
|
return CORE_ERROR;
|
2017-10-19 04:42:07 +00:00
|
|
|
}
|
2017-10-19 03:50:39 +00:00
|
|
|
|
2017-10-19 04:42:07 +00:00
|
|
|
memset(&event, 0, sizeof(event));
|
|
|
|
event.se_assoc_id = SCTP_FUTURE_ASSOC;
|
|
|
|
event.se_on = 1;
|
|
|
|
for (i = 0; i < (int)(sizeof(event_types)/sizeof(c_uint16_t)); i++)
|
2017-10-19 03:50:39 +00:00
|
|
|
{
|
2017-10-19 04:42:07 +00:00
|
|
|
event.se_type = event_types[i];
|
|
|
|
if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_EVENT,
|
2017-10-19 03:50:39 +00:00
|
|
|
&event, sizeof(struct sctp_event)) < 0)
|
|
|
|
{
|
2017-10-20 04:18:58 +00:00
|
|
|
d_error("usrsctp_setsockopt SCTP_EVENT failed");
|
2017-10-19 03:50:39 +00:00
|
|
|
return CORE_ERROR;
|
2017-10-19 04:42:07 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-19 03:50:39 +00:00
|
|
|
|
2017-10-18 16:09:06 +00:00
|
|
|
memset((void *)&local_addr, 0, sizeof(struct sockaddr_in));
|
|
|
|
local_addr.sin_family = AF_INET;
|
|
|
|
local_addr.sin_len = sizeof(struct sockaddr_in);
|
|
|
|
local_addr.sin_port = htons(mme_self()->s1ap_port);
|
2017-10-20 08:19:27 +00:00
|
|
|
local_addr.sin_addr.s_addr = mme_self()->s1ap_addr;
|
2017-10-18 16:09:06 +00:00
|
|
|
|
|
|
|
if (usrsctp_bind(psock, (struct sockaddr *)&local_addr,
|
|
|
|
sizeof(struct sockaddr_in)) == -1)
|
|
|
|
{
|
|
|
|
d_error("usrsctp_bind failed(%s:%d)",
|
|
|
|
INET_NTOP(&mme_self()->s1ap_addr, buf), mme_self()->s1ap_port);
|
|
|
|
return CORE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (usrsctp_listen(psock, 1) < 0)
|
|
|
|
{
|
|
|
|
d_error("usrsctp_listen failed");
|
|
|
|
return CORE_ERROR;
|
|
|
|
}
|
|
|
|
|
2017-10-20 04:18:58 +00:00
|
|
|
rv = thread_create(&accept_thread, NULL, accept_main, NULL);
|
|
|
|
if (rv != CORE_OK) return rv;
|
|
|
|
|
2017-10-18 16:09:06 +00:00
|
|
|
d_trace(1, "s1_enb_listen() %s:%d\n",
|
|
|
|
INET_NTOP(&mme_self()->s1ap_addr, buf), mme_self()->s1ap_port);
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-10-20 07:32:57 +00:00
|
|
|
status_t s1ap_final()
|
2017-10-18 16:09:06 +00:00
|
|
|
{
|
2017-10-20 04:18:58 +00:00
|
|
|
while(usrsctp_finish() != 0)
|
|
|
|
{
|
|
|
|
d_error("try to finsih SCTP\n");
|
|
|
|
core_sleep(time_from_msec(1000));
|
|
|
|
}
|
2017-10-20 07:32:57 +00:00
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t s1ap_close()
|
|
|
|
{
|
|
|
|
struct socket *psock = NULL;
|
|
|
|
|
|
|
|
d_assert(mme_self(), return CORE_ERROR, "Null param");
|
2017-11-22 12:50:08 +00:00
|
|
|
d_assert(mme_self()->s1ap_sock, return CORE_ERROR,
|
2017-10-20 07:32:57 +00:00
|
|
|
"S1-ENB path already opened");
|
|
|
|
|
2017-10-20 22:34:12 +00:00
|
|
|
accept_thread_should_stop = 1;
|
|
|
|
|
2017-10-20 07:32:57 +00:00
|
|
|
psock = (struct socket *)mme_self()->s1ap_sock;
|
|
|
|
usrsctp_close(psock);
|
2017-10-20 22:34:12 +00:00
|
|
|
#if 0
|
|
|
|
thread_delete(accept_thread);
|
|
|
|
#else
|
|
|
|
d_error("[FIXME] should delete accept_thread : "
|
|
|
|
"how to release usrsctp_accept() blocking?");
|
|
|
|
#endif
|
2017-10-18 16:09:06 +00:00
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-11-22 12:50:08 +00:00
|
|
|
status_t s1ap_sctp_close(sock_id sock)
|
2017-10-18 16:09:06 +00:00
|
|
|
{
|
|
|
|
usrsctp_close((struct socket *)sock);
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-11-22 12:50:08 +00:00
|
|
|
status_t s1ap_sendto(sock_id sock, pkbuf_t *pkbuf,
|
2017-10-18 16:09:06 +00:00
|
|
|
c_uint32_t addr, c_uint16_t port)
|
|
|
|
{
|
|
|
|
char buf[INET_ADDRSTRLEN];
|
|
|
|
ssize_t sent;
|
2017-11-22 12:50:08 +00:00
|
|
|
struct socket *psock = (struct socket *)sock;
|
2017-10-19 04:42:07 +00:00
|
|
|
struct sctp_sndinfo sndinfo;
|
2017-10-18 16:09:06 +00:00
|
|
|
|
2017-11-22 12:50:08 +00:00
|
|
|
d_assert(sock, return CORE_ERROR, "Null param");
|
2017-10-18 16:09:06 +00:00
|
|
|
d_assert(pkbuf, return CORE_ERROR, "Null param");
|
|
|
|
|
|
|
|
memset((void *)&sndinfo, 0, sizeof(struct sctp_sndinfo));
|
2017-10-19 04:42:07 +00:00
|
|
|
sndinfo.snd_ppid = htonl(SCTP_S1AP_PPID);
|
2017-10-18 16:09:06 +00:00
|
|
|
sent = usrsctp_sendv(psock, pkbuf->payload, pkbuf->len,
|
2017-10-20 06:46:06 +00:00
|
|
|
NULL, 0, /* Only SOCK_STREAM is supported at this time */
|
2017-10-18 16:09:06 +00:00
|
|
|
(void *)&sndinfo, (socklen_t)sizeof(struct sctp_sndinfo),
|
|
|
|
SCTP_SENDV_SNDINFO, 0);
|
|
|
|
|
|
|
|
d_trace(10,"Sent %d->%d bytes to [%s:%d]\n",
|
|
|
|
pkbuf->len, sent, INET_NTOP(&addr, buf), port);
|
|
|
|
d_trace_hex(10, pkbuf->payload, pkbuf->len);
|
|
|
|
if (sent < 0 || sent != pkbuf->len)
|
|
|
|
{
|
2017-10-20 04:18:58 +00:00
|
|
|
d_error("sent : %d, pkbuf->len : %d\n", sent, pkbuf->len);
|
2017-10-18 16:09:06 +00:00
|
|
|
return CORE_ERROR;
|
|
|
|
}
|
|
|
|
pkbuf_free(pkbuf);
|
|
|
|
|
|
|
|
return CORE_OK;
|
|
|
|
}
|
|
|
|
|
2017-10-20 04:18:58 +00:00
|
|
|
static void *THREAD_FUNC accept_main(thread_id id, void *data)
|
|
|
|
{
|
|
|
|
event_t e;
|
|
|
|
|
|
|
|
struct socket *sock = NULL;
|
|
|
|
struct sockaddr_in remote_addr;
|
|
|
|
socklen_t addr_len;
|
|
|
|
|
|
|
|
while (!accept_thread_should_stop)
|
|
|
|
{
|
|
|
|
if ((sock = usrsctp_accept((struct socket *)mme_self()->s1ap_sock,
|
|
|
|
(struct sockaddr *)&remote_addr, &addr_len)) == NULL)
|
|
|
|
{
|
|
|
|
d_error("usrsctp_accept failed");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
event_set(&e, MME_EVT_S1AP_LO_ACCEPT);
|
|
|
|
event_set_param1(&e, (c_uintptr_t)sock);
|
|
|
|
mme_event_send(&e);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int s1ap_usrsctp_recv_cb(struct socket *sock,
|
|
|
|
union sctp_sockstore addr, void *data, size_t datalen,
|
|
|
|
struct sctp_rcvinfo rcv, int flags, void *ulp_info)
|
|
|
|
{
|
2017-10-20 06:52:30 +00:00
|
|
|
if (data)
|
2017-10-20 06:46:06 +00:00
|
|
|
{
|
|
|
|
if (flags & MSG_NOTIFICATION)
|
|
|
|
{
|
2017-10-20 04:18:58 +00:00
|
|
|
handle_notification((union sctp_notification *)data, datalen);
|
2017-10-20 06:46:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-20 04:18:58 +00:00
|
|
|
c_uint32_t ppid = ntohl(rcv.rcv_ppid);
|
2017-10-20 06:46:06 +00:00
|
|
|
if ((flags & MSG_EOR) && ppid == SCTP_S1AP_PPID)
|
2017-10-20 04:18:58 +00:00
|
|
|
{
|
|
|
|
event_t e;
|
|
|
|
pkbuf_t *pkbuf;
|
|
|
|
|
|
|
|
pkbuf = pkbuf_alloc(0, MAX_SDU_LEN);
|
|
|
|
d_assert(pkbuf, return 1, );
|
|
|
|
|
|
|
|
pkbuf->len = datalen;
|
|
|
|
memcpy(pkbuf->payload, data, pkbuf->len);
|
|
|
|
|
|
|
|
event_set(&e, MME_EVT_S1AP_MESSAGE);
|
|
|
|
event_set_param1(&e, (c_uintptr_t)sock);
|
|
|
|
event_set_param2(&e, (c_uintptr_t)pkbuf);
|
|
|
|
mme_event_send(&e);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d_warn("Unknwon PPID(%d) for data length(%ld)\n",
|
|
|
|
ppid, datalen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-19 04:42:07 +00:00
|
|
|
static void
|
|
|
|
handle_association_change_event(struct sctp_assoc_change *sac)
|
2017-10-18 16:09:06 +00:00
|
|
|
{
|
2017-10-19 04:42:07 +00:00
|
|
|
unsigned int i, n;
|
|
|
|
|
|
|
|
printf("Association change ");
|
|
|
|
switch (sac->sac_state) {
|
|
|
|
case SCTP_COMM_UP:
|
|
|
|
printf("SCTP_COMM_UP");
|
|
|
|
break;
|
|
|
|
case SCTP_COMM_LOST:
|
|
|
|
printf("SCTP_COMM_LOST");
|
|
|
|
break;
|
|
|
|
case SCTP_RESTART:
|
|
|
|
printf("SCTP_RESTART");
|
|
|
|
break;
|
|
|
|
case SCTP_SHUTDOWN_COMP:
|
|
|
|
printf("SCTP_SHUTDOWN_COMP");
|
|
|
|
break;
|
|
|
|
case SCTP_CANT_STR_ASSOC:
|
|
|
|
printf("SCTP_CANT_STR_ASSOC");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("UNKNOWN");
|
|
|
|
break;
|
2017-10-18 16:09:06 +00:00
|
|
|
}
|
2017-10-19 04:42:07 +00:00
|
|
|
printf(", streams (in/out) = (%u/%u)",
|
|
|
|
sac->sac_inbound_streams, sac->sac_outbound_streams);
|
|
|
|
n = sac->sac_length - sizeof(struct sctp_assoc_change);
|
|
|
|
if (((sac->sac_state == SCTP_COMM_UP) ||
|
|
|
|
(sac->sac_state == SCTP_RESTART)) && (n > 0)) {
|
|
|
|
printf(", supports");
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
switch (sac->sac_info[i]) {
|
|
|
|
case SCTP_ASSOC_SUPPORTS_PR:
|
|
|
|
printf(" PR");
|
|
|
|
break;
|
|
|
|
case SCTP_ASSOC_SUPPORTS_AUTH:
|
|
|
|
printf(" AUTH");
|
|
|
|
break;
|
|
|
|
case SCTP_ASSOC_SUPPORTS_ASCONF:
|
|
|
|
printf(" ASCONF");
|
|
|
|
break;
|
|
|
|
case SCTP_ASSOC_SUPPORTS_MULTIBUF:
|
|
|
|
printf(" MULTIBUF");
|
|
|
|
break;
|
|
|
|
case SCTP_ASSOC_SUPPORTS_RE_CONFIG:
|
|
|
|
printf(" RE-CONFIG");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf(" UNKNOWN(0x%02x)", sac->sac_info[i]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (((sac->sac_state == SCTP_COMM_LOST) ||
|
|
|
|
(sac->sac_state == SCTP_CANT_STR_ASSOC)) && (n > 0)) {
|
|
|
|
printf(", ABORT =");
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
printf(" 0x%02x", sac->sac_info[i]);
|
|
|
|
}
|
2017-10-18 16:09:06 +00:00
|
|
|
}
|
2017-10-19 04:42:07 +00:00
|
|
|
printf(".\n");
|
|
|
|
if ((sac->sac_state == SCTP_CANT_STR_ASSOC) ||
|
|
|
|
(sac->sac_state == SCTP_SHUTDOWN_COMP) ||
|
|
|
|
(sac->sac_state == SCTP_COMM_LOST)) {
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2017-10-18 16:09:06 +00:00
|
|
|
|
2017-10-19 04:42:07 +00:00
|
|
|
static void
|
|
|
|
handle_peer_address_change_event(struct sctp_paddr_change *spc)
|
|
|
|
{
|
|
|
|
char addr_buf[INET6_ADDRSTRLEN];
|
|
|
|
const char *addr;
|
|
|
|
struct sockaddr_in *sin;
|
|
|
|
struct sockaddr_in6 *sin6;
|
|
|
|
struct sockaddr_conn *sconn;
|
|
|
|
|
|
|
|
switch (spc->spc_aaddr.ss_family) {
|
|
|
|
case AF_INET:
|
|
|
|
sin = (struct sockaddr_in *)&spc->spc_aaddr;
|
|
|
|
addr = inet_ntop(AF_INET, &sin->sin_addr, addr_buf, INET_ADDRSTRLEN);
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
|
|
|
|
addr = inet_ntop(AF_INET6, &sin6->sin6_addr, addr_buf, INET6_ADDRSTRLEN);
|
|
|
|
break;
|
|
|
|
case AF_CONN:
|
|
|
|
sconn = (struct sockaddr_conn *)&spc->spc_aaddr;
|
|
|
|
#ifdef _WIN32
|
|
|
|
_snprintf(addr_buf, INET6_ADDRSTRLEN, "%p", sconn->sconn_addr);
|
2017-10-19 03:50:39 +00:00
|
|
|
#else
|
2017-10-19 04:42:07 +00:00
|
|
|
snprintf(addr_buf, INET6_ADDRSTRLEN, "%p", sconn->sconn_addr);
|
2017-10-19 03:50:39 +00:00
|
|
|
#endif
|
2017-10-19 04:42:07 +00:00
|
|
|
addr = addr_buf;
|
|
|
|
break;
|
|
|
|
default:
|
2017-10-19 03:50:39 +00:00
|
|
|
#ifdef _WIN32
|
2017-10-19 04:42:07 +00:00
|
|
|
_snprintf(addr_buf, INET6_ADDRSTRLEN, "Unknown family %d", spc->spc_aaddr.ss_family);
|
2017-10-19 03:50:39 +00:00
|
|
|
#else
|
2017-10-19 04:42:07 +00:00
|
|
|
snprintf(addr_buf, INET6_ADDRSTRLEN, "Unknown family %d", spc->spc_aaddr.ss_family);
|
2017-10-19 03:50:39 +00:00
|
|
|
#endif
|
2017-10-19 04:42:07 +00:00
|
|
|
addr = addr_buf;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
printf("Peer address %s is now ", addr);
|
|
|
|
switch (spc->spc_state) {
|
|
|
|
case SCTP_ADDR_AVAILABLE:
|
|
|
|
printf("SCTP_ADDR_AVAILABLE");
|
|
|
|
break;
|
|
|
|
case SCTP_ADDR_UNREACHABLE:
|
|
|
|
printf("SCTP_ADDR_UNREACHABLE");
|
|
|
|
break;
|
|
|
|
case SCTP_ADDR_REMOVED:
|
|
|
|
printf("SCTP_ADDR_REMOVED");
|
|
|
|
break;
|
|
|
|
case SCTP_ADDR_ADDED:
|
|
|
|
printf("SCTP_ADDR_ADDED");
|
|
|
|
break;
|
|
|
|
case SCTP_ADDR_MADE_PRIM:
|
|
|
|
printf("SCTP_ADDR_MADE_PRIM");
|
|
|
|
break;
|
|
|
|
case SCTP_ADDR_CONFIRMED:
|
|
|
|
printf("SCTP_ADDR_CONFIRMED");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("UNKNOWN");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
printf(" (error = 0x%08x).\n", spc->spc_error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
handle_send_failed_event(struct sctp_send_failed_event *ssfe)
|
|
|
|
{
|
|
|
|
size_t i, n;
|
|
|
|
|
|
|
|
if (ssfe->ssfe_flags & SCTP_DATA_UNSENT) {
|
|
|
|
printf("Unsent ");
|
|
|
|
}
|
|
|
|
if (ssfe->ssfe_flags & SCTP_DATA_SENT) {
|
|
|
|
printf("Sent ");
|
|
|
|
}
|
|
|
|
if (ssfe->ssfe_flags & ~(SCTP_DATA_SENT | SCTP_DATA_UNSENT)) {
|
|
|
|
printf("(flags = %x) ", ssfe->ssfe_flags);
|
|
|
|
}
|
|
|
|
printf("message with PPID = %u, SID = %u, flags: 0x%04x due to error = 0x%08x",
|
|
|
|
ntohl(ssfe->ssfe_info.snd_ppid), ssfe->ssfe_info.snd_sid,
|
|
|
|
ssfe->ssfe_info.snd_flags, ssfe->ssfe_error);
|
|
|
|
n = ssfe->ssfe_length - sizeof(struct sctp_send_failed_event);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
printf(" 0x%02x", ssfe->ssfe_data[i]);
|
|
|
|
}
|
|
|
|
printf(".\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
handle_notification(union sctp_notification *notif, size_t n)
|
|
|
|
{
|
|
|
|
if (notif->sn_header.sn_length != (uint32_t)n) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (notif->sn_header.sn_type) {
|
|
|
|
case SCTP_ASSOC_CHANGE:
|
|
|
|
handle_association_change_event(&(notif->sn_assoc_change));
|
|
|
|
break;
|
|
|
|
case SCTP_PEER_ADDR_CHANGE:
|
|
|
|
handle_peer_address_change_event(&(notif->sn_paddr_change));
|
|
|
|
break;
|
|
|
|
case SCTP_REMOTE_ERROR:
|
|
|
|
break;
|
|
|
|
case SCTP_SHUTDOWN_EVENT:
|
|
|
|
break;
|
|
|
|
case SCTP_ADAPTATION_INDICATION:
|
|
|
|
break;
|
|
|
|
case SCTP_PARTIAL_DELIVERY_EVENT:
|
|
|
|
break;
|
|
|
|
case SCTP_AUTHENTICATION_EVENT:
|
|
|
|
break;
|
|
|
|
case SCTP_SENDER_DRY_EVENT:
|
|
|
|
break;
|
|
|
|
case SCTP_NOTIFICATIONS_STOPPED_EVENT:
|
|
|
|
break;
|
|
|
|
case SCTP_SEND_FAILED_EVENT:
|
|
|
|
handle_send_failed_event(&(notif->sn_send_failed_event));
|
|
|
|
break;
|
|
|
|
case SCTP_STREAM_RESET_EVENT:
|
|
|
|
break;
|
|
|
|
case SCTP_ASSOC_RESET_EVENT:
|
|
|
|
break;
|
|
|
|
case SCTP_STREAM_CHANGE_EVENT:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-18 16:09:06 +00:00
|
|
|
static void debug_printf(const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
vprintf(format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|