diff options
author | Pablo Neira Ayuso <pablo@gnumonks.org> | 2011-11-06 20:47:08 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2011-11-08 11:17:44 +0100 |
commit | 2b5d3ce7c69e1149bb2af815ab8b8534026063ca (patch) | |
tree | adf544975a45d2bbcc7e46f3269aff101f1ed0bb /src/ipa.c | |
parent | ffe3cb3ef93483c45d23ba7ea7fe156d5bb4dbc6 (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.c | 204 |
1 files changed, 204 insertions, 0 deletions
@@ -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; +} |