diff options
Diffstat (limited to 'src/gsup_server.c')
-rw-r--r-- | src/gsup_server.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/gsup_server.c b/src/gsup_server.c new file mode 100644 index 0000000..41a03f4 --- /dev/null +++ b/src/gsup_server.c @@ -0,0 +1,204 @@ +#include <errno.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/linuxlist.h> +#include <osmocom/abis/ipa.h> +#include <osmocom/abis/ipaccess.h> + +#include "gsup_server.h" + +static void osmo_gsup_server_send(struct osmo_gsup_conn *conn, + int proto_ext, struct msgb *msg_tx) +{ + ipa_prepend_header_ext(msg_tx, proto_ext); + ipa_msg_push_header(msg_tx, IPAC_PROTO_OSMO); + ipa_server_conn_send(conn->conn, msg_tx); +} + +int osmo_gsup_conn_send(struct osmo_gsup_conn *conn, struct msgb *msg) +{ + if (!conn) { + msgb_free(msg); + return -ENOTCONN; + } + + osmo_gsup_server_send(conn, IPAC_PROTO_EXT_GSUP, msg); + + return 0; +} + +static int osmo_gsup_conn_oap_handle(struct osmo_gsup_conn *conn, + struct msgb *msg_rx) +{ + int rc; + struct msgb *msg_tx; +#if 0 + rc = oap_handle(&conn->oap_state, msg_rx, &msg_tx); + msgb_free(msg_rx); + if (rc < 0) + return rc; + + if (msg_tx) + osmo_gsup_conn_send(conn, IPAC_PROTO_EXT_OAP, msg_tx); +#endif + return 0; +} + + +/* Data from a given client has arrived over the socket */ +static int osmo_gsup_server_read_cb(struct ipa_server_conn *conn, + struct msgb *msg) +{ + struct ipaccess_head *hh = (struct ipaccess_head *) msg->data; + struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg); + struct osmo_gsup_conn *clnt = (struct osmo_gsup_conn *)conn->data; + int rc; + static struct ipaccess_unit ipa_dev = { + .unit_name = "HLR", + /* FIXME */ + }; + + msg->l2h = &hh->data[0]; + + /* FIXME: not BTS for server side? */ +#if 0 + rc = ipaccess_bts_handle_ccm(conn, &ipa_dev, msg); + + if (rc < 0) { + LOGP(DLGSUP, LOGL_NOTICE, + "GSUP received an invalid IPA/CCM message from %s:%d\n", + conn->addr, conn->port); + /* Link has been closed */ + clnt->is_connected = 0; + msgb_free(msg); + return -1; + } + + if (rc == 1) { + uint8_t msg_type = *(msg->l2h); + /* CCM message */ + if (msg_type == IPAC_MSGT_PONG) { + LOGP(DLGSUP, LOGL_DEBUG, "GSUP receiving PONG\n"); + clnt->got_ipa_pong = 1; + } + + msgb_free(msg); + return 0; + } +#endif + + if (hh->proto != IPAC_PROTO_OSMO) + goto invalid; + + if (!he || msgb_l2len(msg) < sizeof(*he)) + goto invalid; + + msg->l2h = &he->data[0]; + + if (he->proto == IPAC_PROTO_EXT_GSUP) { + OSMO_ASSERT(clnt->server->read_cb != NULL); + clnt->server->read_cb(clnt, msg); + /* expecting read_cb() to free msg */ + } else if (he->proto == IPAC_PROTO_EXT_OAP) { + return osmo_gsup_conn_oap_handle(clnt, msg); + /* osmo_gsup_client_oap_handle frees msg */ + } else + goto invalid; + + return 0; + +invalid: + LOGP(DLGSUP, LOGL_NOTICE, + "GSUP received an invalid IPA message from %s:%d, size = %d\n", + conn->addr, conn->port, msgb_length(msg)); + msgb_free(msg); + return -1; + +} + +static int osmo_gsup_server_closed_cb(struct ipa_server_conn *conn) +{ + struct osmo_gsup_conn *clnt = (struct osmo_gsup_conn *)conn->data; + + LOGP(DLGSUP, LOGL_INFO, "Lost GSUP client %s:%d\n", + conn->addr, conn->port); + + llist_del(&clnt->list); + + return 0; +} + +/* a client has connected to the server socket and we have accept()ed it */ +static int osmo_gsup_server_accept_cb(struct ipa_server_link *link, int fd) +{ + struct osmo_gsup_conn *conn; + struct osmo_gsup_server *gsups = + (struct osmo_gsup_server *) link->data; + + conn = talloc_zero(link->data, struct osmo_gsup_conn); + OSMO_ASSERT(conn); + + conn->conn = ipa_server_conn_create(conn, link, fd, + osmo_gsup_server_read_cb, + osmo_gsup_server_closed_cb, conn); + OSMO_ASSERT(conn->conn); + + /* link data structure with server structure */ + conn->server = gsups; + llist_add_tail(&conn->list, &gsups->clients); + + LOGP(DLGSUP, LOGL_INFO, "New GSUP client %s:%d\n", + conn->conn->addr, conn->conn->port); +#if 0 + rc = oap_init(&gsups->oap_config, &conn->oap_state); + if (rc != 0) + goto failed; +failed: +#endif + return 0; +} + +struct osmo_gsup_server * +osmo_gsup_server_create(void *ctx, const char *ip_addr, + uint16_t tcp_port, + osmo_gsup_read_cb_t read_cb) +{ + struct osmo_gsup_server *gsups; + int rc; + + gsups = talloc_zero(ctx, struct osmo_gsup_server); + OSMO_ASSERT(gsups); + + INIT_LLIST_HEAD(&gsups->clients); + + gsups->link = ipa_server_link_create(gsups, + /* no e1inp */ NULL, + ip_addr, tcp_port, + osmo_gsup_server_accept_cb, + gsups); + if (!gsups->link) + goto failed; + + gsups->read_cb = read_cb; + + rc = ipa_server_link_open(gsups->link); + if (rc < 0) + goto failed; + + return gsups; + +failed: + osmo_gsup_server_destroy(gsups); + return NULL; +} + +void osmo_gsup_server_destroy(struct osmo_gsup_server *gsups) +{ + if (gsups->link) { + ipa_server_link_close(gsups->link); + ipa_server_link_destroy(gsups->link); + gsups->link = NULL; + } + talloc_free(gsups); +} |