Support CBSP/TCP and SBc-AP/SCTP client mode
This patch adds support to set up a CBSP link so that osmo-cbc connects as a TCP client to the BSC, which runs as a TCP server. Similary, support to set up a SBc-AP link so that osmo-cbc connects as a SCTP client to the MME, which runs as SCTP server. A new "mode (client|server|disabled)" VTY command is added to use one mother or the other, and also to disable the link and hence the peer until it is set again. This is useful if the peer is under manintenance for instance. client sockets are created automatically when the "peer" vty node is exited if the link is not yet created, hence creating it at startup or if moved back from "disabled" mode. If client socket dies, it will keep attempting reconnect every 5 seconds. Related: OS#4945 Change-Id: I3ec54b615b41b56f7a9c64298e3fcaac37f4b60e
This commit is contained in:
parent
5044524f01
commit
3ef5020007
|
@ -16,9 +16,11 @@ cbc
|
|||
local-ip ::1
|
||||
local-port 29168
|
||||
peer cbsp example-bsc
|
||||
mode server
|
||||
remote-ip 127.0.0.2
|
||||
remote-port 48049
|
||||
peer sbcap example-mme
|
||||
mode client
|
||||
remote-ip 127.0.0.2
|
||||
remote-ip ::2
|
||||
remote-port 29168
|
||||
|
|
|
@ -19,6 +19,16 @@ enum cbc_peer_protocol {
|
|||
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_peer {
|
|||
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 @@ void cbc_peer_remove(struct cbc_peer *peer);
|
|||
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);
|
||||
|
|
|
@ -31,19 +31,22 @@ int cbc_cbsp_mgr_open_srv(struct cbc_cbsp_mgr *mgr);
|
|||
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);
|
||||
|
|
|
@ -33,15 +33,20 @@ int cbc_sbcap_mgr_open_srv(struct cbc_sbcap_mgr *mgr);
|
|||
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);
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <osmocom/cbc/debug.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;
|
||||
|
@ -99,6 +100,11 @@ static int cbc_vty_go_parent(struct vty *vty)
|
|||
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;
|
||||
|
|
116
src/cbc_peer.c
116
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 @@ const struct value_string cbc_peer_proto_name[] = {
|
|||
{ 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 @@ struct cbc_peer *cbc_peer_by_addr_proto(const char *remote_host, uint16_t remote
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -593,6 +593,19 @@ DEFUN_DEPRECATED(cfg_peer_proto, cfg_peer_proto_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_ATTR(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",
|
||||
CMD_ATTR_NODE_EXIT)
|
||||
{
|
||||
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 +690,7 @@ static void write_one_peer(struct vty *vty, struct cbc_peer *peer)
|
|||
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 +743,7 @@ void cbc_vty_init(void)
|
|||
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);
|
||||
|
|
159
src/cbsp_link.c
159
src/cbsp_link.c
|
@ -46,6 +46,7 @@ struct cbc_cbsp_link *cbc_cbsp_link_alloc(struct cbc_cbsp_mgr *cbc, struct cbc_p
|
|||
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,122 @@ void cbc_cbsp_link_free(struct cbc_cbsp_link *link)
|
|||
|
||||
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");
|
||||
osmo_fsm_inst_dispatch(link->fi, CBSP_LINK_E_CMD_RESET, NULL);
|
||||
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 +230,7 @@ static int cbsp_cbc_read_cb(struct osmo_stream_srv *conn)
|
|||
}
|
||||
|
||||
/* 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 +275,23 @@ static int cbsp_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
|||
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 +301,11 @@ static int cbsp_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
|||
}
|
||||
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 +339,21 @@ void cbc_cbsp_link_tx(struct cbc_cbsp_link *link, struct osmo_cbsp_decoded *cbsp
|
|||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
179
src/sbcap_link.c
179
src/sbcap_link.c
|
@ -50,6 +50,7 @@ struct cbc_sbcap_link *cbc_sbcap_link_alloc(struct cbc_sbcap_mgr *cbc, struct cb
|
|||
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,145 @@ const char *cbc_sbcap_link_name(const struct cbc_sbcap_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;
|
||||
}
|
||||
|
||||
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");
|
||||
osmo_fsm_inst_dispatch(link->fi, SBcAP_LINK_E_CMD_RESET, NULL);
|
||||
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 +283,7 @@ out:
|
|||
}
|
||||
|
||||
/* 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 +328,23 @@ static int sbcap_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
|||
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 +355,10 @@ static int sbcap_cbc_accept_cb(struct osmo_stream_srv_link *srv_link, int fd)
|
|||
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 +391,23 @@ void cbc_sbcap_link_tx(struct cbc_sbcap_link *link, SBcAP_SBC_AP_PDU_t *pdu)
|
|||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue