aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2021-12-01 19:42:43 +0100
committerPau Espin Pedrol <pespin@sysmocom.de>2021-12-09 20:21:33 +0100
commit82a52f6a7d39672f1a67941d9e9a380ab59fcb92 (patch)
tree02dc0ed16ed0170c17c6b2a5e7c0e2ee8a9ac457
parent4b6ce34083e62c5f50e0b665011c668aa041ecc4 (diff)
prim: Add internal CTL SAPI to negotiate SAP versions
This commits adds a generic mechanism for applications to validate support for SAPs and specific versions of them. A new special SAPI is introduced to manage inbound control messages for the protocol. In that SAPI a new primitive HELLO.req/.cnf is added to negotiate support for versions of any given SAP. The idea is that the client upon connecting submits a HELLO.req(SAP, VER) for each SAP it plans to use, including the version of the special CTL SAPI itself (preferrably to be checked first). Upon receiving such a message, osmo_prim_srv handles it using a special path, which ends up calling the user provided rx_sapi_version_cb(SAP, VER). In there, the user can either: * Accept the version (return same VER value) * Reject the requested version but propose another candidate version (return some positive VER value other than received VER). In this case, the client can decide whether to request another VER or close the connection. * Reject the proposed version and close the connection. Change-Id: I0c2d92cfdb5433e3caab51d712fd947d51eeef23
-rw-r--r--include/osmocom/netif/prim.h10
-rw-r--r--src/prim.c115
2 files changed, 122 insertions, 3 deletions
diff --git a/include/osmocom/netif/prim.h b/include/osmocom/netif/prim.h
index 4f17622..78406dd 100644
--- a/include/osmocom/netif/prim.h
+++ b/include/osmocom/netif/prim.h
@@ -31,6 +31,15 @@ typedef int (*osmo_prim_srv_conn_cb)(struct osmo_prim_srv *prim_srv);
/*! oph and related msgb is owned by srv and wll be freed after the callback returns. */
typedef int (*osmo_prim_srv_rx_cb)(struct osmo_prim_srv *prim_srv, struct osmo_prim_hdr *oph);
+/*! Return value:
+ * RET=rem_version: Accept the version
+ * RET!=rem_version && RET > 0: Reject the requested version but propose another candidate version
+ * In this case, the client can decide whether to request another VER
+ * or close the connection.
+ * RET<0: Reject the proposed version and close the connection.
+ */
+typedef int (*osmo_prim_srv_rx_sapi_version)(struct osmo_prim_srv *prim_srv, uint32_t sapi, uint16_t rem_version);
+
struct osmo_prim_hdr *osmo_prim_msgb_alloc(unsigned int sap, unsigned int primitive,
enum osmo_prim_operation operation, size_t alloc_len);
@@ -43,6 +52,7 @@ void *osmo_prim_srv_link_get_priv(const struct osmo_prim_srv_link *prim_link);
void osmo_prim_srv_link_set_log_category(struct osmo_prim_srv_link *prim_link, int log_cat);
void osmo_prim_srv_link_set_opened_conn_cb(struct osmo_prim_srv_link *prim_link, osmo_prim_srv_conn_cb opened_conn_cb);
void osmo_prim_srv_link_set_closed_conn_cb(struct osmo_prim_srv_link *prim_link, osmo_prim_srv_conn_cb closed_conn_cb);
+void osmo_prim_srv_link_set_rx_sapi_version_cb(struct osmo_prim_srv_link *prim_link, osmo_prim_srv_rx_sapi_version rx_sapi_version_cb);
void osmo_prim_srv_link_set_rx_cb(struct osmo_prim_srv_link *prim_link, osmo_prim_srv_rx_cb rx_cb);
void osmo_prim_srv_link_set_rx_msgb_alloc_len(struct osmo_prim_srv_link *prim_link, size_t alloc_len);
int osmo_prim_srv_link_open(struct osmo_prim_srv_link *prim_link);
diff --git a/src/prim.c b/src/prim.c
index 6c6da6e..5189c4c 100644
--- a/src/prim.c
+++ b/src/prim.c
@@ -82,6 +82,7 @@ struct osmo_prim_srv_link {
struct osmo_stream_srv_link *stream;
osmo_prim_srv_conn_cb opened_conn_cb;
osmo_prim_srv_conn_cb closed_conn_cb;
+ osmo_prim_srv_rx_sapi_version rx_sapi_version_cb;
osmo_prim_srv_rx_cb rx_cb;
size_t rx_msgb_alloc_len;
};
@@ -93,10 +94,107 @@ struct osmo_prim_srv {
};
/******************************
+ * CONTROL SAP
+ ******************************/
+#define OSMO_PRIM_CTL_SAPI 0xffffffff
+#define OSMO_PRIM_CTL_API_VERSION 0
+
+enum sap_ctl_prim_type {
+ SAP_CTL_PRIM_HELLO,
+ _SAP_CTL_PRIM_MAX
+};
+
+const struct value_string sap_ctl_prim_type_names[] = {
+ OSMO_VALUE_STRING(SAP_CTL_PRIM_HELLO),
+ { 0, NULL }
+};
+
+/* HNB_CTL_PRIM_HELLO.ind, UL */
+struct sap_ctl_hello_param {
+ uint32_t sapi; /* SAPI for which we negotiate version */
+ uint16_t api_version; /* The intended version */
+} __attribute__ ((packed));
+
+struct sap_ctl_prim {
+ struct osmo_prim_hdr hdr;
+ union {
+ struct sap_ctl_hello_param hello_req;
+ struct sap_ctl_hello_param hello_cnf;
+ } u;
+} __attribute__ ((packed));
+
+static struct sap_ctl_prim *_sap_ctl_makeprim_hello_cnf(uint32_t sapi, uint16_t api_version)
+{
+ struct sap_ctl_prim *ctl_prim;
+
+ ctl_prim = (struct sap_ctl_prim *)osmo_prim_msgb_alloc(
+ OSMO_PRIM_CTL_SAPI, SAP_CTL_PRIM_HELLO, PRIM_OP_CONFIRM,
+ sizeof(struct osmo_prim_hdr) + sizeof(struct sap_ctl_hello_param));
+ msgb_put(ctl_prim->hdr.msg, sizeof(struct sap_ctl_hello_param));
+ ctl_prim->u.hello_cnf.sapi = sapi;
+ ctl_prim->u.hello_cnf.api_version = api_version;
+
+ return ctl_prim;
+}
+
+/******************************
* osmo_prim_srv
******************************/
#define LOGSRV(srv, lvl, fmt, args...) LOGP((srv)->link->log_cat, lvl, fmt, ## args)
+static int _srv_sap_ctl_rx_hello_req(struct osmo_prim_srv *prim_srv, struct sap_ctl_hello_param *hello_ind)
+{
+ struct sap_ctl_prim *prim_resp;
+ int rc;
+
+ LOGSRV(prim_srv, LOGL_INFO, "Rx CTL-HELLO.req SAPI=%u API_VERSION=%u\n", hello_ind->sapi, hello_ind->api_version);
+
+ if (hello_ind->sapi == OSMO_PRIM_CTL_SAPI)
+ rc = hello_ind->api_version == OSMO_PRIM_CTL_API_VERSION ? OSMO_PRIM_CTL_API_VERSION : -1;
+ else if (prim_srv->link->rx_sapi_version_cb)
+ rc = prim_srv->link->rx_sapi_version_cb(prim_srv, hello_ind->sapi, hello_ind->api_version);
+ else /* Accept whatever version by default: */
+ rc = hello_ind->api_version;
+
+ if (rc < 0) {
+ LOGSRV(prim_srv, LOGL_ERROR,
+ "SAPI=%u API_VERSION=%u not supported! destroying connection\n",
+ hello_ind->sapi, hello_ind->api_version);
+ osmo_stream_srv_set_flush_and_destroy(prim_srv->stream);
+ return rc;
+ }
+ prim_resp = _sap_ctl_makeprim_hello_cnf(hello_ind->sapi, (uint16_t)rc);
+ LOGSRV(prim_srv, LOGL_INFO, "Tx CTL-HELLO.cnf SAPI=%u API_VERSION=%u\n",
+ hello_ind->sapi, prim_resp->u.hello_cnf.api_version);
+ osmo_prim_srv_send(prim_srv, prim_resp->hdr.msg);
+ return rc;
+}
+
+static int _srv_sap_ctl_rx(struct osmo_prim_srv *prim_srv, struct osmo_prim_hdr *oph)
+{
+ switch (oph->operation) {
+ case PRIM_OP_REQUEST:
+ switch (oph->primitive) {
+ case SAP_CTL_PRIM_HELLO:
+ return _srv_sap_ctl_rx_hello_req(prim_srv, (struct sap_ctl_hello_param *)msgb_data(oph->msg));
+ default:
+ LOGSRV(prim_srv, LOGL_ERROR, "Rx unknown CTL SAP primitive %u (len=%u)\n",
+ oph->primitive, msgb_length(oph->msg));
+ return -EINVAL;
+ }
+ break;
+ case PRIM_OP_RESPONSE:
+ case PRIM_OP_INDICATION:
+ case PRIM_OP_CONFIRM:
+ default:
+ LOGSRV(prim_srv, LOGL_ERROR, "Rx CTL SAP unexpected primitive operation %s-%s (len=%u)\n",
+ get_value_string(sap_ctl_prim_type_names, oph->primitive),
+ get_value_string(osmo_prim_op_names, oph->operation),
+ msgb_length(oph->msg));
+ return -EINVAL;
+ }
+}
+
static int _osmo_prim_srv_read_cb(struct osmo_stream_srv *srv)
{
struct osmo_prim_srv *prim_srv = osmo_stream_srv_get_data(srv);
@@ -133,9 +231,15 @@ static int _osmo_prim_srv_read_cb(struct osmo_stream_srv *srv)
osmo_prim_init(&oph, pkth->sap, pkth->primitive, pkth->operation, msg);
msgb_pull(msg, sizeof(*pkth));
- if (prim_srv->link->rx_cb)
- rc = prim_srv->link->rx_cb(prim_srv, &oph);
-
+ switch (oph.sap) {
+ case OSMO_PRIM_CTL_SAPI:
+ rc = _srv_sap_ctl_rx(prim_srv, &oph);
+ break;
+ default:
+ if (prim_srv->link->rx_cb)
+ rc = prim_srv->link->rx_cb(prim_srv, &oph);
+ break;
+ }
/* as we always synchronously process the message in _osmo_prim_srv_link_rx() and
* its callbacks, we can free the message here. */
msgb_free(msg);
@@ -325,6 +429,11 @@ void osmo_prim_srv_link_set_closed_conn_cb(struct osmo_prim_srv_link *prim_link,
prim_link->closed_conn_cb = closed_conn_cb;
}
+void osmo_prim_srv_link_set_rx_sapi_version_cb(struct osmo_prim_srv_link *prim_link, osmo_prim_srv_rx_sapi_version rx_sapi_version_cb)
+{
+ prim_link->rx_sapi_version_cb = rx_sapi_version_cb;
+}
+
void osmo_prim_srv_link_set_rx_cb(struct osmo_prim_srv_link *prim_link, osmo_prim_srv_rx_cb rx_cb)
{
prim_link->rx_cb = rx_cb;