aboutsummaryrefslogtreecommitdiffstats
path: root/src/ipa.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@gnumonks.org>2011-11-06 20:47:08 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2011-11-08 11:17:44 +0100
commit2b5d3ce7c69e1149bb2af815ab8b8534026063ca (patch)
treeadf544975a45d2bbcc7e46f3269aff101f1ed0bb /src/ipa.c
parentffe3cb3ef93483c45d23ba7ea7fe156d5bb4dbc6 (diff)
src: add generic channel infrastructure and A-bis IPA server support
This patch adds the generic channel infrastructure that allows to create channel of different types. Each channel has their own configuration functions. struct osmo_chan *chan; chan = osmo_chan_create(tall_example, CHAN_ABIS_IPA_SERVER); ... /* specific configuration functions per supported channel. */ osmo_chan_abis_ipa_server_set_cb_signalmsg(chan, signal_msg_cb); osmo_chan_abis_ipa_unit_add(chan, 1801, 0); /* open channel. */ osmo_chan_open(chan); The input path requires a callback to be registered. The output path is handled through: int osmo_chan_enqueue(struct osmo_chan *c, struct msgb *msg); The msg->dst must be set (it can be taken from the original message to route one reply). This patch also adds A-bis IPA server support. It has been tested with e1inp_ipa_bsc_test available in libosmo-abis.
Diffstat (limited to 'src/ipa.c')
-rw-r--r--src/ipa.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/ipa.c b/src/ipa.c
index 27df56f..a4c3a5f 100644
--- a/src/ipa.c
+++ b/src/ipa.c
@@ -1,13 +1,69 @@
#include <stdlib.h>
#include <arpa/inet.h>
+#include <string.h>
+#include <unistd.h>
#include <errno.h>
+#include <osmocom/core/linuxlist.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/msgb.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/talloc.h>
+
+#include <osmocom/gsm/tlv.h>
+
+#include <osmocom/netif/channel.h>
#include <osmocom/netif/ipa.h>
#define IPA_ALLOC_SIZE 1200
+/*
+ * Common propietary IPA messages:
+ * - PONG: in reply to PING.
+ * - ID_REQUEST: first messages once OML has been established.
+ * - ID_ACK: in reply to ID_ACK.
+ */
+const uint8_t ipa_pong_msg[] = {
+ 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG
+};
+
+const uint8_t ipa_id_ack_msg[] = {
+ 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
+};
+
+const uint8_t ipa_id_req_msg[] = {
+ 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
+ 0x01, IPAC_IDTAG_UNIT,
+ 0x01, IPAC_IDTAG_MACADDR,
+ 0x01, IPAC_IDTAG_LOCATION1,
+ 0x01, IPAC_IDTAG_LOCATION2,
+ 0x01, IPAC_IDTAG_EQUIPVERS,
+ 0x01, IPAC_IDTAG_SWVERSION,
+ 0x01, IPAC_IDTAG_UNITNAME,
+ 0x01, IPAC_IDTAG_SERNR,
+};
+
+static const char *idtag_names[] = {
+ [IPAC_IDTAG_SERNR] = "Serial_Number",
+ [IPAC_IDTAG_UNITNAME] = "Unit_Name",
+ [IPAC_IDTAG_LOCATION1] = "Location_1",
+ [IPAC_IDTAG_LOCATION2] = "Location_2",
+ [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
+ [IPAC_IDTAG_SWVERSION] = "Software_Version",
+ [IPAC_IDTAG_IPADDR] = "IP_Address",
+ [IPAC_IDTAG_MACADDR] = "MAC_Address",
+ [IPAC_IDTAG_UNIT] = "Unit_ID",
+};
+
+const char *ipaccess_idtag_name(uint8_t tag)
+{
+ if (tag >= ARRAY_SIZE(idtag_names))
+ return "unknown";
+
+ return idtag_names[tag];
+}
+
+
struct msgb *osmo_ipa_msg_alloc(int headroom)
{
struct msgb *msg;
@@ -68,3 +124,151 @@ int osmo_ipa_msg_recv(int fd, struct msgb *msg)
msgb_put(msg, ret);
return ret;
}
+
+int osmo_ipa_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
+{
+ uint8_t t_len;
+ uint8_t t_tag;
+ uint8_t *cur = buf;
+
+ memset(dec, 0, sizeof(*dec));
+
+ while (len >= 2) {
+ len -= 2;
+ t_len = *cur++;
+ t_tag = *cur++;
+
+ if (t_len > len + 1) {
+ LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d\n", t_len);
+ return -EINVAL;
+ }
+
+ DEBUGPC(DLMI, "%s='%s' ", ipaccess_idtag_name(t_tag), cur);
+
+ dec->lv[t_tag].len = t_len;
+ dec->lv[t_tag].val = cur;
+
+ cur += t_len;
+ len -= t_len;
+ }
+ return 0;
+}
+
+int osmo_ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data)
+{
+ unsigned long ul;
+ char *endptr;
+ const char *nptr;
+
+ nptr = str;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ unit_data->site_id = ul & 0xffff;
+
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ unit_data->bts_id = ul & 0xffff;
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ unit_data->trx_id = ul & 0xffff;
+
+ return 0;
+}
+
+static int ipaccess_send(int fd, const void *msg, size_t msglen)
+{
+ int ret;
+
+ ret = write(fd, msg, msglen);
+ if (ret < 0)
+ return ret;
+ if (ret < msglen) {
+ LOGP(DLINP, LOGL_ERROR, "ipaccess_send: short write\n");
+ return -EIO;
+ }
+ return ret;
+}
+
+int ipaccess_send_pong(int fd)
+{
+ return ipaccess_send(fd, ipa_pong_msg, sizeof(ipa_pong_msg));
+}
+
+int ipaccess_send_id_ack(int fd)
+{
+ return ipaccess_send(fd, ipa_id_ack_msg, sizeof(ipa_id_ack_msg));
+}
+
+int ipaccess_send_id_req(int fd)
+{
+ return ipaccess_send(fd, ipa_id_req_msg, sizeof(ipa_id_req_msg));
+}
+
+/* base handling of the ip.access protocol */
+int osmo_ipa_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd)
+{
+ int ipa_ccm = 0;
+ uint8_t msg_type = *(msg->l2h);
+ int ret = 0;
+
+ switch (msg_type) {
+ case IPAC_MSGT_PING:
+ ipa_ccm = 1;
+ ret = ipaccess_send_pong(bfd->fd);
+ break;
+ case IPAC_MSGT_PONG:
+ DEBUGP(DLMI, "PONG!\n");
+ ipa_ccm = 1;
+ break;
+ case IPAC_MSGT_ID_ACK:
+ DEBUGP(DLMI, "ID_ACK? -> ACK!\n");
+ ipa_ccm = 1;
+ ret = ipaccess_send_id_ack(bfd->fd);
+ break;
+ }
+ return ipa_ccm;
+}
+
+int ipaccess_parse_unitid(const char *str, struct ipaccess_unit *unit_data)
+{
+ unsigned long ul;
+ char *endptr;
+ const char *nptr;
+
+ nptr = str;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ unit_data->site_id = ul & 0xffff;
+
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ unit_data->bts_id = ul & 0xffff;
+
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ unit_data->trx_id = ul & 0xffff;
+
+ return 0;
+}