pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-cbc/+/28732 )
Change subject: WIP: support TCP/SCTP clients
......................................................................
WIP: support TCP/SCTP clients
Change-Id: I3ec54b615b41b56f7a9c64298e3fcaac37f4b60e
---
M include/osmocom/cbc/cbc_peer.h
M include/osmocom/cbc/cbsp_link.h
M include/osmocom/cbc/sbcap_link.h
M src/cbc_main.c
M src/cbc_peer.c
M src/cbc_vty.c
M src/cbsp_link.c
M src/sbcap_link.c
8 files changed, 473 insertions(+), 32 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-cbc refs/changes/32/28732/1
diff --git a/include/osmocom/cbc/cbc_peer.h b/include/osmocom/cbc/cbc_peer.h
index 785ea09..cf2a578 100644
--- a/include/osmocom/cbc/cbc_peer.h
+++ b/include/osmocom/cbc/cbc_peer.h
@@ -19,6 +19,16 @@
CBC_PEER_PROTO_SBcAP
};
+enum cbc_peer_link_mode {
+ CBC_PEER_LINK_MODE_DISABLED = 0,
+ CBC_PEER_LINK_MODE_SERVER,
+ CBC_PEER_LINK_MODE_CLIENT,
+};
+
+extern const struct value_string cbc_peer_link_mode_names[];
+static inline const char *cbc_peer_link_mode_name(enum cbc_peer_link_mode val)
+{ return get_value_string(cbc_peer_link_mode_names, val); }
+
struct cbc_peer {
struct llist_head list; /* linked to cbc.peers */
const char *name;
@@ -34,6 +44,7 @@
struct cbc_sabp_link *sabp;
struct cbc_sbcap_link *sbcap;
} link;
+ enum cbc_peer_link_mode link_mode;
};
extern const struct value_string cbc_peer_proto_name[];
@@ -44,3 +55,4 @@
struct cbc_peer *cbc_peer_by_name(const char *name);
struct cbc_peer *cbc_peer_by_addr_proto(const char *remote_host, uint16_t remote_port,
enum cbc_peer_protocol proto);
+int cbc_peer_apply_cfg_chg(struct cbc_peer *peer);
diff --git a/include/osmocom/cbc/cbsp_link.h b/include/osmocom/cbc/cbsp_link.h
index 7fcacdf..ad5fa71 100644
--- a/include/osmocom/cbc/cbsp_link.h
+++ b/include/osmocom/cbc/cbsp_link.h
@@ -30,19 +30,22 @@
struct cbc_cbsp_link {
/* entry in osmo_cbsp_cbc.links */
struct llist_head list;
- /* stream server connection for this link */
- struct osmo_stream_srv *conn;
/* partially received CBSP message (rx completion pending) */
struct msgb *rx_msg;
-
struct osmo_fsm_inst *fi;
-
struct cbc_peer *peer;
+ bool is_client;
+ union {
+ struct osmo_stream_srv *srv_conn;
+ struct osmo_stream_cli *cli_conn;
+ void *conn; /* used when we just care about the pointer */
+ };
};
struct cbc_cbsp_link *cbc_cbsp_link_alloc(struct cbc_cbsp_mgr *cbc, struct cbc_peer
*peer);
void cbc_cbsp_link_free(struct cbc_cbsp_link *link);
const char *cbc_cbsp_link_name(const struct cbc_cbsp_link *link);
+int cbc_cbsp_link_open_cli(struct cbc_cbsp_link *link);
void cbc_cbsp_link_tx(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *cbsp);
void cbc_cbsp_link_close(struct cbc_cbsp_link *link);
int cbc_cbsp_link_rx_cb(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *dec);
diff --git a/include/osmocom/cbc/sbcap_link.h b/include/osmocom/cbc/sbcap_link.h
index 5946544..6185e3d 100644
--- a/include/osmocom/cbc/sbcap_link.h
+++ b/include/osmocom/cbc/sbcap_link.h
@@ -32,15 +32,20 @@
struct cbc_sbcap_link {
/* entry in osmo_sbcap_cbc.links */
struct llist_head list;
- /* stream server connection for this link */
- struct osmo_stream_srv *conn;
struct osmo_fsm_inst *fi;
struct cbc_peer *peer;
+ bool is_client;
+ union {
+ struct osmo_stream_srv *srv_conn;
+ struct osmo_stream_cli *cli_conn;
+ void *conn; /* used when we just care about the pointer */
+ };
};
struct cbc_sbcap_link *cbc_sbcap_link_alloc(struct cbc_sbcap_mgr *cbc, struct cbc_peer
*peer);
void cbc_sbcap_link_free(struct cbc_sbcap_link *link);
const char *cbc_sbcap_link_name(const struct cbc_sbcap_link *link);
+int cbc_sbcap_link_open_cli(struct cbc_sbcap_link *link);
void cbc_sbcap_link_tx(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu);
void cbc_sbcap_link_close(struct cbc_sbcap_link *link);
int cbc_sbcap_link_rx_cb(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu);
diff --git a/src/cbc_main.c b/src/cbc_main.c
index cd80e31..4198383 100644
--- a/src/cbc_main.c
+++ b/src/cbc_main.c
@@ -50,6 +50,7 @@
#include <osmocom/cbc/sbcap_link.h>
#include <osmocom/cbc/cbc_data.h>
#include <osmocom/cbc/cbc_vty.h>
+#include <osmocom/cbc/cbc_peer.h>
static void *tall_cbc_ctx;
struct cbc *g_cbc;
@@ -95,6 +96,11 @@
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
+ case PEER_NODE:
+ cbc_peer_apply_cfg_chg((struct cbc_peer *)vty->index);
+ vty->node = CONFIG_NODE;
+ vty->index = NULL;
+ break;
default:
vty->node = CONFIG_NODE;
vty->index = NULL;
@@ -276,6 +282,7 @@
exit(1);
}
+ /* TODO: split create into create and open_server */
if (!(g_cbc->cbsp.mgr = cbc_cbsp_mgr_create(tall_cbc_ctx))) {
perror("Error binding CBSP port");
exit(1);
diff --git a/src/cbc_peer.c b/src/cbc_peer.c
index e8b79f9..e8e730d 100644
--- a/src/cbc_peer.c
+++ b/src/cbc_peer.c
@@ -32,6 +32,7 @@
#include <osmocom/cbc/cbc_peer.h>
#include <osmocom/cbc/cbsp_link.h>
#include <osmocom/cbc/sbcap_link.h>
+#include <osmocom/cbc/debug.h>
const struct value_string cbc_peer_proto_name[] = {
{ CBC_PEER_PROTO_CBSP, "CBSP" },
@@ -40,6 +41,14 @@
{ 0, NULL }
};
+
+const struct value_string cbc_peer_link_mode_names[] = {
+ { CBC_PEER_LINK_MODE_DISABLED, "disabled" },
+ { CBC_PEER_LINK_MODE_SERVER, "server" },
+ { CBC_PEER_LINK_MODE_CLIENT, "client" },
+ {}
+};
+
/* create a new cbc_peer */
struct cbc_peer *cbc_peer_create(const char *name, enum cbc_peer_protocol proto)
{
@@ -120,3 +129,110 @@
}
return NULL;
}
+
+static int cbc_peer_apply_cfg_chg_cbsp(struct cbc_peer *peer)
+{
+ struct cbc_cbsp_link *link = peer->link.cbsp;
+ int rc = 0;
+
+ switch (peer->link_mode) {
+ case CBC_PEER_LINK_MODE_DISABLED:
+ if (link) {
+ LOGPCC(link, LOGL_NOTICE,
+ "link mode changed to 'disabled', closing active link\n");
+ cbc_cbsp_link_close(link);
+ }
+ /* Nothing to be done, cbc_cbsp_mgr->srv_link will refuse
+ * accepting() disabled peers. */
+ OSMO_ASSERT(!peer->link.cbsp);
+ break;
+ case CBC_PEER_LINK_MODE_SERVER:
+ if (link && link->is_client) {
+ LOGPCC(link, LOGL_NOTICE,
+ "link mode changed 'client' -> 'server', closing active
link\n");
+ cbc_cbsp_link_close(link);
+ }
+ /* Nothing to be done, cbc_cbsp_mgr->srv_link will accept() and
+ * recreate the link */
+ OSMO_ASSERT(!peer->link.cbsp);
+ break;
+ case CBC_PEER_LINK_MODE_CLIENT:
+ if (link) {
+ if (link->is_client) {
+ /* nothing to be done, cli link already created */
+ break;
+ }
+ LOGPCC(link, LOGL_NOTICE,
+ "link mode changed 'server' -> 'client', closing active
link\n");
+ cbc_cbsp_link_close(link);
+ }
+ OSMO_ASSERT(!peer->link.cbsp);
+ link = cbc_cbsp_link_alloc(g_cbc->cbsp.mgr, peer);
+ peer->link.cbsp = link;
+ rc = cbc_cbsp_link_open_cli(link);
+ break;
+ }
+ return rc;
+}
+
+static int cbc_peer_apply_cfg_chg_sbcap(struct cbc_peer *peer)
+{
+ struct cbc_sbcap_link *link = peer->link.sbcap;
+ int rc = 0;
+
+ switch (peer->link_mode) {
+ case CBC_PEER_LINK_MODE_DISABLED:
+ if (link) {
+ LOGPSBCAPC(link, LOGL_NOTICE,
+ "link mode changed to 'disabled', closing active link\n");
+ cbc_sbcap_link_close(link);
+ }
+ /* Nothing to be done, cbc_sbcap_mgr->srv_link will refuse
+ * accepting() disabled peers. */
+ OSMO_ASSERT(!peer->link.sbcap);
+ break;
+ case CBC_PEER_LINK_MODE_SERVER:
+ if (link && link->is_client) {
+ LOGPSBCAPC(link, LOGL_NOTICE,
+ "link mode changed 'client' -> 'server', closing active
link\n");
+ cbc_sbcap_link_close(link);
+ }
+ /* Nothing to be done, cbc_sbcap_mgr->srv_link will accept() and
+ * recreate the link */
+ OSMO_ASSERT(!peer->link.sbcap);
+ break;
+ case CBC_PEER_LINK_MODE_CLIENT:
+ if (link) {
+ if (link->is_client) {
+ /* nothing to be done, cli link already created */
+ break;
+ }
+ LOGPSBCAPC(link, LOGL_NOTICE,
+ "link mode changed 'server' -> 'client', closing active
link\n");
+ cbc_sbcap_link_close(link);
+ }
+ OSMO_ASSERT(!peer->link.sbcap);
+ link = cbc_sbcap_link_alloc(g_cbc->sbcap.mgr, peer);
+ peer->link.sbcap = link;
+ rc = cbc_sbcap_link_open_cli(link);
+ break;
+ }
+ return rc;
+}
+
+int cbc_peer_apply_cfg_chg(struct cbc_peer *peer)
+{
+ int rc = -ENOTSUP;
+
+ switch (peer->proto) {
+ case CBC_PEER_PROTO_CBSP:
+ rc = cbc_peer_apply_cfg_chg_cbsp(peer);
+ break;
+ case CBC_PEER_PROTO_SBcAP:
+ rc = cbc_peer_apply_cfg_chg_sbcap(peer);
+ break;
+ case CBC_PEER_PROTO_SABP:
+ break;
+ }
+ return rc;
+}
diff --git a/src/cbc_vty.c b/src/cbc_vty.c
index 7e5a9db..b8e8fc3 100644
--- a/src/cbc_vty.c
+++ b/src/cbc_vty.c
@@ -593,6 +593,18 @@
return CMD_SUCCESS;
}
+DEFUN(cfg_peer_mode, cfg_peer_mode_cmd,
+ "mode (server|client|disabled)",
+ "Connect to peer as TCP(CBSP)/SCTP(SBc-AP) server or client\n"
+ "server: listen for inbound TCP (CBSP) / SCTP (SBc-AP) connections from a remote
peer\n"
+ "client: establish outbound TCP (CBSP) / SCTP (SBc-AP) connection to a remote
peer\n"
+ "Disable CBSP link\n")
+{
+ struct cbc_peer *peer = (struct cbc_peer *) vty->index;
+ peer->link_mode = get_string_value(cbc_peer_link_mode_names, argv[0]);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_peer_remote_port, cfg_peer_remote_port_cmd,
"remote-port <0-65535>",
"Configure remote (TCP) port of peer\n"
@@ -677,6 +689,7 @@
unsigned int i;
vty_out(vty, " peer %s %s%s", get_value_string(cbc_peer_proto_name_vty,
peer->proto),
peer->name, VTY_NEWLINE);
+ vty_out(vty, " mode %s%s", cbc_peer_link_mode_name(peer->link_mode),
VTY_NEWLINE);
if (peer->remote_port == -1)
vty_out(vty, " no remote-port%s", VTY_NEWLINE);
else
@@ -729,6 +742,7 @@
install_element(CBC_NODE, &cfg_cbc_no_peer_cmd);
install_node(&peer_node, NULL);
install_element(PEER_NODE, &cfg_peer_proto_cmd);
+ install_element(PEER_NODE, &cfg_peer_mode_cmd);
install_element(PEER_NODE, &cfg_peer_remote_port_cmd);
install_element(PEER_NODE, &cfg_peer_no_remote_port_cmd);
install_element(PEER_NODE, &cfg_peer_remote_ip_cmd);
diff --git a/src/cbsp_link.c b/src/cbsp_link.c
index cd1c308..94cf4cc 100644
--- a/src/cbsp_link.c
+++ b/src/cbsp_link.c
@@ -46,6 +46,7 @@
OSMO_ASSERT(link);
link->peer = peer;
+ link->is_client = (peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
link->fi = osmo_fsm_inst_alloc(&cbsp_link_fsm, link, link, LOGL_DEBUG, NULL);
if (!link->fi) {
@@ -70,18 +71,121 @@
const char *cbc_cbsp_link_name(const struct cbc_cbsp_link *link)
{
+ struct osmo_fd *ofd;
OSMO_ASSERT(link);
- if (link->peer && link->peer->name) {
+ if (link->peer && link->peer->name)
return link->peer->name;
- } else {
- struct osmo_fd *ofd = osmo_stream_srv_get_ofd(link->conn);
- return osmo_sock_get_name2(ofd->fd);
- }
+
+ if (link->is_client)
+ ofd = osmo_stream_cli_get_ofd(link->cli_conn);
+ else
+ ofd = osmo_stream_srv_get_ofd(link->srv_conn);
+ return osmo_sock_get_name2(ofd->fd);
}
+/*
+ * TCP client
+ */
+static int cbc_cbsp_link_cli_connect_cb(struct osmo_stream_cli *conn)
+{
+ struct cbc_cbsp_link *link = osmo_stream_cli_get_data(conn);
+ LOGPCC(link, LOGL_NOTICE, "Connected\n");
+ return 0;
+}
+
+static int cbc_cbsp_link_cli_disconnect_cb(struct osmo_stream_cli *conn)
+{
+ struct cbc_cbsp_link *link = osmo_stream_cli_get_data(conn);
+ LOGPCC(link, LOGL_NOTICE, "Disconnected.\n");
+ LOGPCC(link, LOGL_NOTICE, "Reconnecting...\n");
+ osmo_stream_cli_reconnect(conn);
+ return 0;
+}
+
+static int cbc_cbsp_link_cli_read_cb(struct osmo_stream_cli *conn)
+{
+ struct cbc_cbsp_link *link = osmo_stream_cli_get_data(conn);
+ struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn);
+ struct osmo_cbsp_decoded *decoded;
+ struct msgb *msg = NULL;
+ int rc;
+
+ LOGPCC(link, LOGL_DEBUG, "read_cb rx_msg=%p\n", link->rx_msg);
+
+ /* message de-segmentation */
+ rc = osmo_cbsp_recv_buffered(conn, ofd->fd, &msg, &link->rx_msg);
+ if (rc <= 0) {
+ if (rc == -EAGAIN || rc == -EINTR) {
+ /* more data needs to be read */
+ return 0;
+ } else if (rc == -EPIPE || rc == -ECONNRESET) {
+ /* lost connection with server */
+ } else if (rc == 0) {
+ /* connection closed with server */
+ }
+ /* destroy connection */
+ cbc_cbsp_link_close(link);
+ return -EBADF;
+ }
+ OSMO_ASSERT(msg);
+ LOGPCC(link, LOGL_DEBUG, "Received CBSP %s\n", msgb_hexdump(msg));
+ /* decode + dispatch message */
+ decoded = osmo_cbsp_decode(link, msg);
+ if (decoded) {
+ LOGPCC(link, LOGL_INFO, "Received CBSP %s\n",
+ get_value_string(cbsp_msg_type_names, decoded->msg_type));
+ g_cbc->cbsp.mgr->rx_cb(link, decoded);
+ } else {
+ LOGPCC(link, LOGL_ERROR, "Unable to decode %s\n", msgb_hexdump(msg));
+ }
+ msgb_free(msg);
+ return 0;
+}
+
+int cbc_cbsp_link_open_cli(struct cbc_cbsp_link *link)
+{
+ struct osmo_stream_cli *conn;
+ struct cbc_peer *peer = link->peer;
+ int rc;
+
+ OSMO_ASSERT(link->is_client);
+ OSMO_ASSERT(peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
+
+ conn = osmo_stream_cli_create(link);
+ osmo_stream_cli_set_data(conn, link);
+ osmo_stream_cli_set_nodelay(conn, true);
+ osmo_stream_cli_set_reconnect_timeout(conn, 5);
+ osmo_stream_cli_set_proto(conn, IPPROTO_TCP);
+ osmo_stream_cli_set_connect_cb(conn, cbc_cbsp_link_cli_connect_cb);
+ osmo_stream_cli_set_disconnect_cb(conn, cbc_cbsp_link_cli_disconnect_cb);
+ osmo_stream_cli_set_read_cb(conn, cbc_cbsp_link_cli_read_cb);
+ rc = osmo_stream_cli_set_local_addrs(conn, (const char
**)&g_cbc->config.cbsp.local_host, 1);
+ if (rc < 0)
+ goto free_ret;
+ /* We assign free local port for client links:
+ * osmo_stream_cli_set_local_port(conn, g_cbc->cbsp.local_port);
+ */
+ OSMO_ASSERT(peer->num_remote_host > 0);
+ rc = osmo_stream_cli_set_addrs(conn, (const char**)peer->remote_host,
peer->num_remote_host);
+ if (rc < 0)
+ goto free_ret;
+ osmo_stream_cli_set_port(conn, peer->remote_port);
+ rc = osmo_stream_cli_open(conn);
+ if (rc < 0)
+ goto free_ret;
+ link->cli_conn = conn;
+ return 0;
+free_ret:
+ osmo_stream_cli_destroy(conn);
+ return rc;
+}
+
+/*
+ * TCP server
+ */
/* data from BSC has arrived at CBC */
-static int cbsp_cbc_read_cb(struct osmo_stream_srv *conn)
+static int cbsp_cbc_srv_read_cb(struct osmo_stream_srv *conn)
{
struct osmo_stream_srv_link *srv_link = osmo_stream_srv_get_master(conn);
struct cbc_cbsp_link *link = osmo_stream_srv_get_data(conn);
@@ -125,7 +229,7 @@
}
/* connection from BSC to CBC has been closed */
-static int cbsp_cbc_closed_cb(struct osmo_stream_srv *conn)
+static int cbsp_cbc_srv_closed_cb(struct osmo_stream_srv *conn)
{
struct cbc_cbsp_link *link = osmo_stream_srv_get_data(conn);
LOGPCC(link, LOGL_NOTICE, "connection closed\n");
@@ -170,6 +274,23 @@
peer = cbc_peer_create(NULL, CBC_PEER_PROTO_CBSP);
OSMO_ASSERT(peer);
peer->unknown_dynamic_peer = true;
+ } else { /* peer is known */
+ switch (peer->link_mode) {
+ case CBC_PEER_LINK_MODE_DISABLED:
+ LOGP(DCBSP, LOGL_NOTICE,
+ "Rejecting conn for disabled CBSP peer %s:%d\n",
+ remote_ip, remote_port);
+ close(fd);
+ return -1;
+ case CBC_PEER_LINK_MODE_CLIENT:
+ LOGP(DCBSP, LOGL_NOTICE,
+ "Rejecting conn for CBSP peer %s:%d configured as 'client'\n",
+ remote_ip, remote_port);
+ close(fd);
+ return -1;
+ default: /* MODE_SERVER */
+ break;
+ }
}
if (peer->link.cbsp) {
LOGPCC(peer->link.cbsp, LOGL_ERROR,
@@ -179,10 +300,11 @@
}
link = cbc_cbsp_link_alloc(cbc, peer);
OSMO_ASSERT(link);
- link->conn = osmo_stream_srv_create(srv_link, srv_link, fd,
- cbsp_cbc_read_cb, cbsp_cbc_closed_cb,
- link);
- if (!link->conn) {
+
+ link->srv_conn = osmo_stream_srv_create(srv_link, srv_link, fd,
+ cbsp_cbc_srv_read_cb, cbsp_cbc_srv_closed_cb,
+ link);
+ if (!link->srv_conn) {
LOGPCC(link, LOGL_ERROR,
"Unable to create stream server for %s:%u\n",
remote_ip, remote_port);
@@ -216,13 +338,21 @@
return;
}
talloc_free(cbsp);
- osmo_stream_srv_send(link->conn, msg);
+ if (link->is_client)
+ osmo_stream_cli_send(link->cli_conn, msg);
+ else
+ osmo_stream_srv_send(link->srv_conn, msg);
}
void cbc_cbsp_link_close(struct cbc_cbsp_link *link)
{
- if (link->conn)
- osmo_stream_srv_destroy(link->conn);
+ if (!link->conn)
+ return;
+
+ if (link->is_client)
+ osmo_stream_cli_destroy(link->cli_conn);
+ else
+ osmo_stream_srv_destroy(link->srv_conn);
}
/* initialize the CBC-side CBSP server */
diff --git a/src/sbcap_link.c b/src/sbcap_link.c
index 9194509..b6f5415 100644
--- a/src/sbcap_link.c
+++ b/src/sbcap_link.c
@@ -50,6 +50,7 @@
OSMO_ASSERT(link);
link->peer = peer;
+ link->is_client = (peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
link->fi = osmo_fsm_inst_alloc(&sbcap_link_fsm, link, link, LOGL_DEBUG, NULL);
if (!link->fi) {
@@ -77,16 +78,144 @@
struct osmo_fd *ofd;
OSMO_ASSERT(link);
- if (link->peer && link->peer->name) {
+ if (link->peer && link->peer->name)
return link->peer->name;
- }
- ofd = osmo_stream_srv_get_ofd(link->conn);
+ if (link->is_client)
+ ofd = osmo_stream_cli_get_ofd(link->cli_conn);
+ else
+ ofd = osmo_stream_srv_get_ofd(link->srv_conn);
return osmo_sock_get_name2(ofd->fd);
}
+/*
+ * SCTP client
+ */
+static int cbc_sbcap_link_cli_connect_cb(struct osmo_stream_cli *conn)
+{
+ struct cbc_sbcap_link *link = osmo_stream_cli_get_data(conn);
+ LOGPSBCAPC(link, LOGL_NOTICE, "Connected\n");
+ return 0;
+}
+
+static int cbc_sbcap_link_cli_disconnect_cb(struct osmo_stream_cli *conn)
+{
+ struct cbc_sbcap_link *link = osmo_stream_cli_get_data(conn);
+ LOGPSBCAPC(link, LOGL_NOTICE, "Disconnected.\n");
+ LOGPSBCAPC(link, LOGL_NOTICE, "Reconnecting...\n");
+ osmo_stream_cli_reconnect(conn);
+ return 0;
+}
+
+static int cbc_sbcap_link_cli_read_cb(struct osmo_stream_cli *conn)
+{
+ struct cbc_sbcap_link *link = osmo_stream_cli_get_data(conn);
+ struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn);
+ SBcAP_SBC_AP_PDU_t *pdu;
+ struct msgb *msg = msgb_alloc_c(g_cbc, 1500, "SBcAP-rx");
+ struct sctp_sndrcvinfo sinfo;
+ int flags = 0;
+ int rc;
+
+ /* read SBc-AP message from socket and process it */
+ rc = sctp_recvmsg(ofd->fd, msgb_data(msg), msgb_tailroom(msg),
+ NULL, NULL, &sinfo, &flags);
+ LOGPSBCAPC(link, LOGL_DEBUG, "%s(): sctp_recvmsg() returned %d
(flags=0x%x)\n",
+ __func__, rc, flags);
+ if (rc < 0) {
+ osmo_stream_cli_reconnect(conn);
+ goto out;
+ } else if (rc == 0) {
+ osmo_stream_cli_reconnect(conn);
+ } else {
+ msgb_put(msg, rc);
+ }
+
+ if (flags & MSG_NOTIFICATION) {
+ union sctp_notification *notif = (union sctp_notification *) msgb_data(msg);
+ LOGPSBCAPC(link, LOGL_DEBUG, "Rx sctp notif %s\n",
+ osmo_sctp_sn_type_str(notif->sn_header.sn_type));
+ switch (notif->sn_header.sn_type) {
+ case SCTP_SHUTDOWN_EVENT:
+ osmo_stream_cli_reconnect(conn);
+ break;
+ case SCTP_ASSOC_CHANGE:
+ LOGPSBCAPC(link, LOGL_DEBUG, "Rx sctp notif SCTP_ASSOC_CHANGE: %s\n",
+ osmo_sctp_assoc_chg_str(notif->sn_assoc_change.sac_state));
+ break;
+ default:
+ LOGPSBCAPC(link, LOGL_DEBUG, "Rx sctp notif %s (%u)\n",
+ osmo_sctp_sn_type_str(notif->sn_header.sn_type),
+ notif->sn_header.sn_type);
+ break;
+ }
+ rc = 0;
+ }
+
+ if (rc == 0)
+ goto out;
+
+ LOGPSBCAPC(link, LOGL_DEBUG, "Received SBc-AP %s\n", msgb_hexdump(msg));
+
+ /* decode + dispatch message */
+ pdu = sbcap_decode(msg);
+ if (pdu) {
+ LOGPSBCAPC(link, LOGL_INFO, "Received SBc-AP %d\n",
+ pdu->present);
+ g_cbc->sbcap.mgr->rx_cb(link, pdu);
+ } else {
+ LOGPSBCAPC(link, LOGL_ERROR, "Unable to decode %s\n", msgb_hexdump(msg));
+ }
+out:
+ msgb_free(msg);
+ return rc;
+}
+
+int cbc_sbcap_link_open_cli(struct cbc_sbcap_link *link)
+{
+ struct osmo_stream_cli *conn;
+ struct cbc_peer *peer = link->peer;
+ int rc;
+
+ OSMO_ASSERT(link->is_client);
+ OSMO_ASSERT(peer->link_mode == CBC_PEER_LINK_MODE_CLIENT);
+
+ conn = osmo_stream_cli_create(link);
+ osmo_stream_cli_set_data(conn, link);
+ osmo_stream_cli_set_nodelay(conn, true);
+ osmo_stream_cli_set_reconnect_timeout(conn, 5);
+ osmo_stream_cli_set_proto(conn, IPPROTO_SCTP);
+ osmo_stream_cli_set_connect_cb(conn, cbc_sbcap_link_cli_connect_cb);
+ osmo_stream_cli_set_disconnect_cb(conn, cbc_sbcap_link_cli_disconnect_cb);
+ osmo_stream_cli_set_read_cb(conn, cbc_sbcap_link_cli_read_cb);
+ OSMO_ASSERT(g_cbc->config.sbcap.num_local_host > 0);
+ rc = osmo_stream_cli_set_local_addrs(conn, (const char
**)&g_cbc->config.sbcap.local_host,
+ g_cbc->config.sbcap.num_local_host);
+ if (rc < 0)
+ goto free_ret;
+ /* We assign free local port for client links:
+ * osmo_stream_cli_set_local_port(conn, g_cbc->sbcap.local_port);
+ */
+ OSMO_ASSERT(peer->num_remote_host > 0);
+ rc = osmo_stream_cli_set_addrs(conn, (const char**)peer->remote_host,
peer->num_remote_host);
+ if (rc < 0)
+ goto free_ret;
+ osmo_stream_cli_set_port(conn, peer->remote_port);
+ rc = osmo_stream_cli_open(conn);
+ if (rc < 0)
+ goto free_ret;
+ link->cli_conn = conn;
+ return 0;
+free_ret:
+ osmo_stream_cli_destroy(conn);
+ return rc;
+}
+
+/*
+ * SCTP server
+ */
/* data from MME has arrived at CBC */
-static int sbcap_cbc_read_cb(struct osmo_stream_srv *conn)
+static int sbcap_cbc_srv_read_cb(struct osmo_stream_srv *conn)
{
struct osmo_stream_srv_link *srv_link = osmo_stream_srv_get_master(conn);
struct cbc_sbcap_link *link = osmo_stream_srv_get_data(conn);
@@ -153,7 +282,7 @@
}
/* connection from MME to CBC has been closed */
-static int sbcap_cbc_closed_cb(struct osmo_stream_srv *conn)
+static int sbcap_cbc_srv_closed_cb(struct osmo_stream_srv *conn)
{
struct cbc_sbcap_link *link = osmo_stream_srv_get_data(conn);
LOGPSBCAPC(link, LOGL_NOTICE, "connection closed\n");
@@ -198,6 +327,23 @@
peer = cbc_peer_create(NULL, CBC_PEER_PROTO_SBcAP);
OSMO_ASSERT(peer);
peer->unknown_dynamic_peer = true;
+ } else { /* peer is known */
+ switch (peer->link_mode) {
+ case CBC_PEER_LINK_MODE_DISABLED:
+ LOGP(DSBcAP, LOGL_NOTICE,
+ "Rejecting conn for disabled SBc-AP peer %s:%d\n",
+ remote_ip, remote_port);
+ close(fd);
+ return -1;
+ case CBC_PEER_LINK_MODE_CLIENT:
+ LOGP(DSBcAP, LOGL_NOTICE,
+ "Rejecting conn for SBc-AP peer %s:%d configured as
'client'\n",
+ remote_ip, remote_port);
+ close(fd);
+ return -1;
+ default: /* MODE_SERVER */
+ break;
+ }
}
if (peer->link.sbcap) {
LOGPSBCAPC(peer->link.sbcap, LOGL_ERROR,
@@ -208,10 +354,10 @@
link = cbc_sbcap_link_alloc(cbc, peer);
OSMO_ASSERT(link);
- link->conn = osmo_stream_srv_create(srv_link, srv_link, fd,
- sbcap_cbc_read_cb, sbcap_cbc_closed_cb,
- link);
- if (!link->conn) {
+ link->srv_conn = osmo_stream_srv_create(srv_link, srv_link, fd,
+ sbcap_cbc_srv_read_cb, sbcap_cbc_srv_closed_cb,
+ link);
+ if (!link->srv_conn) {
LOGPSBCAPC(link, LOGL_ERROR,
"Unable to create stream server for %s:%u\n",
remote_ip, remote_port);
@@ -244,15 +390,23 @@
if (!msg)
goto ret_free;
LOGPSBCAPC(link, LOGL_DEBUG, "Encoded message: %s\n", msgb_hexdump(msg));
- osmo_stream_srv_send(link->conn, msg);
+ if (link->is_client)
+ osmo_stream_cli_send(link->cli_conn, msg);
+ else
+ osmo_stream_srv_send(link->srv_conn, msg);
ret_free:
sbcap_pdu_free(pdu);
}
void cbc_sbcap_link_close(struct cbc_sbcap_link *link)
{
- if (link->conn)
- osmo_stream_srv_destroy(link->conn);
+ if (!link->conn)
+ return;
+
+ if (link->is_client)
+ osmo_stream_cli_destroy(link->cli_conn);
+ else
+ osmo_stream_srv_destroy(link->srv_conn);
}
/* initialize the CBC-side SBc-AP server */
--
To view, visit
https://gerrit.osmocom.org/c/osmo-cbc/+/28732
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-cbc
Gerrit-Branch: master
Gerrit-Change-Id: I3ec54b615b41b56f7a9c64298e3fcaac37f4b60e
Gerrit-Change-Number: 28732
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: newchange