2012-08-15 21:09:39 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/core/select.h>
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
|
|
|
|
#include <osmocom/gsm/tlv.h>
|
|
|
|
|
|
|
|
#include <osmocom/netif/channel.h>
|
|
|
|
#include <osmocom/netif/stream.h>
|
|
|
|
#include <osmocom/netif/ipa.h>
|
|
|
|
#include <osmocom/netif/ipa_unit.h>
|
|
|
|
|
2012-08-18 22:12:18 +00:00
|
|
|
#define CHAN_SIGN_OML 0
|
|
|
|
#define CHAN_SIGN_RSL 1
|
|
|
|
|
2012-08-15 21:09:39 +00:00
|
|
|
/* default IPA cli ports. */
|
|
|
|
#define IPA_TCP_PORT_OML 3002
|
|
|
|
#define IPA_TCP_PORT_RSL 3003
|
|
|
|
|
|
|
|
static void *abis_ipa_cli_tall;
|
|
|
|
|
|
|
|
struct chan_abis_ipa_cli {
|
2012-08-19 17:20:43 +00:00
|
|
|
struct osmo_ipa_unit *unit;
|
2012-08-15 21:09:39 +00:00
|
|
|
|
|
|
|
struct osmo_stream_cli *oml;
|
|
|
|
struct osmo_stream_cli *rsl;
|
|
|
|
|
|
|
|
void (*signal_msg)(struct msgb *msg, int type);
|
|
|
|
};
|
|
|
|
|
|
|
|
static int oml_read_cb(struct osmo_stream_cli *conn);
|
|
|
|
static int rsl_read_cb(struct osmo_stream_cli *conn);
|
|
|
|
|
|
|
|
static int chan_abis_ipa_cli_create(struct osmo_chan *chan)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data;
|
|
|
|
|
2012-08-19 17:20:43 +00:00
|
|
|
c->unit = osmo_ipa_unit_alloc(0);
|
2012-08-15 21:09:39 +00:00
|
|
|
if (c->unit == NULL)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
c->oml = osmo_stream_cli_create(abis_ipa_cli_tall);
|
|
|
|
if (c->oml == NULL)
|
|
|
|
goto err_oml;
|
|
|
|
|
|
|
|
/* default address and port for OML. */
|
|
|
|
osmo_stream_cli_set_addr(c->oml, "0.0.0.0");
|
|
|
|
osmo_stream_cli_set_port(c->oml, IPA_TCP_PORT_OML);
|
|
|
|
osmo_stream_cli_set_read_cb(c->oml, oml_read_cb);
|
|
|
|
osmo_stream_cli_set_data(c->oml, chan);
|
|
|
|
|
|
|
|
c->rsl = osmo_stream_cli_create(abis_ipa_cli_tall);
|
|
|
|
if (c->rsl == NULL)
|
|
|
|
goto err_rsl;
|
|
|
|
|
|
|
|
/* default address and port for RSL. */
|
|
|
|
osmo_stream_cli_set_addr(c->rsl, "0.0.0.0");
|
|
|
|
osmo_stream_cli_set_port(c->rsl, IPA_TCP_PORT_RSL);
|
|
|
|
osmo_stream_cli_set_read_cb(c->rsl, rsl_read_cb);
|
|
|
|
osmo_stream_cli_set_data(c->rsl, chan);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
err_rsl:
|
|
|
|
osmo_stream_cli_destroy(c->oml);
|
|
|
|
err_oml:
|
|
|
|
osmo_ipa_unit_free(c->unit);
|
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void chan_abis_ipa_cli_destroy(struct osmo_chan *chan)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data;
|
|
|
|
|
|
|
|
osmo_ipa_unit_free(c->unit);
|
|
|
|
talloc_free(c->rsl);
|
|
|
|
talloc_free(c->oml);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int chan_abis_ipa_cli_open(struct osmo_chan *chan)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data;
|
|
|
|
struct osmo_fd *ofd;
|
|
|
|
int ret, on = 1;
|
|
|
|
|
|
|
|
if (osmo_stream_cli_open(c->oml) < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
ofd = osmo_stream_cli_get_ofd(c->oml);
|
|
|
|
ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
|
|
|
if (ret < 0)
|
|
|
|
goto err_oml;
|
|
|
|
|
|
|
|
if (osmo_stream_cli_open(c->rsl) < 0)
|
|
|
|
goto err_oml;
|
|
|
|
|
|
|
|
ofd = osmo_stream_cli_get_ofd(c->rsl);
|
|
|
|
ret = setsockopt(ofd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
|
|
|
|
if (ret < 0)
|
|
|
|
goto err_rsl;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_rsl:
|
|
|
|
osmo_stream_cli_close(c->rsl);
|
|
|
|
err_oml:
|
|
|
|
osmo_stream_cli_close(c->oml);
|
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void chan_abis_ipa_cli_close(struct osmo_chan *chan)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *c = (struct chan_abis_ipa_cli *)chan->data;
|
|
|
|
|
|
|
|
osmo_stream_cli_close(c->oml);
|
|
|
|
osmo_stream_cli_close(c->rsl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int chan_abis_ipa_cli_enqueue(struct osmo_chan *c, struct msgb *msg)
|
|
|
|
{
|
|
|
|
osmo_stream_cli_send(msg->dst, msg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void osmo_abis_ipa_cli_set_oml_addr(struct osmo_chan *c, const char *addr)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data;
|
|
|
|
|
|
|
|
osmo_stream_cli_set_addr(s->oml, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void osmo_abis_ipa_cli_set_oml_port(struct osmo_chan *c, uint16_t port)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data;
|
|
|
|
|
|
|
|
osmo_stream_cli_set_port(s->oml, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
void osmo_abis_ipa_cli_set_rsl_addr(struct osmo_chan *c, const char *addr)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data;
|
|
|
|
|
|
|
|
osmo_stream_cli_set_addr(s->rsl, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void osmo_abis_ipa_cli_set_rsl_port(struct osmo_chan *c, uint16_t port)
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data;
|
|
|
|
|
|
|
|
osmo_stream_cli_set_port(s->rsl, port);
|
|
|
|
}
|
|
|
|
|
2012-08-19 17:20:43 +00:00
|
|
|
void osmo_abis_ipa_cli_set_unit(struct osmo_chan *c, struct osmo_ipa_unit *unit)
|
2012-08-15 22:31:40 +00:00
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data;
|
|
|
|
|
|
|
|
osmo_ipa_unit_free(s->unit);
|
|
|
|
s->unit = unit;
|
|
|
|
}
|
|
|
|
|
2012-08-15 21:09:39 +00:00
|
|
|
void osmo_abis_ipa_cli_set_cb_signalmsg(struct osmo_chan *c,
|
|
|
|
void (*signal_msg)(struct msgb *msg, int type))
|
|
|
|
{
|
|
|
|
struct chan_abis_ipa_cli *s = (struct chan_abis_ipa_cli *)&c->data;
|
|
|
|
|
|
|
|
s->signal_msg = signal_msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct msgb *
|
2012-08-19 17:20:43 +00:00
|
|
|
ipa_cli_id_resp(struct osmo_ipa_unit *dev, uint8_t *data, int len)
|
2012-08-15 21:09:39 +00:00
|
|
|
{
|
|
|
|
struct msgb *nmsg;
|
|
|
|
char str[64];
|
|
|
|
uint8_t *tag;
|
|
|
|
|
|
|
|
nmsg = osmo_ipa_msg_alloc(0);
|
|
|
|
if (nmsg == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*msgb_put(nmsg, 1) = IPAC_MSGT_ID_RESP;
|
|
|
|
while (len) {
|
|
|
|
if (len < 2) {
|
|
|
|
LOGP(DLINP, LOGL_NOTICE,
|
|
|
|
"Short read of ipaccess tag\n");
|
|
|
|
msgb_free(nmsg);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
switch (data[1]) {
|
|
|
|
case IPAC_IDTAG_UNIT:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
case IPAC_IDTAG_MACADDR:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf_mac_addr(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
case IPAC_IDTAG_LOCATION1:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf_loc1(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
case IPAC_IDTAG_LOCATION2:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf_loc2(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
case IPAC_IDTAG_EQUIPVERS:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf_hwvers(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
case IPAC_IDTAG_SWVERSION:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf_swvers(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
case IPAC_IDTAG_UNITNAME:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf_name(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
case IPAC_IDTAG_SERNR:
|
2012-08-19 17:20:43 +00:00
|
|
|
osmo_ipa_unit_snprintf_serno(str, sizeof(str), dev);
|
2012-08-15 21:09:39 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
LOGP(DLINP, LOGL_NOTICE,
|
|
|
|
"Unknown ipaccess tag 0x%02x\n", *data);
|
|
|
|
msgb_free(nmsg);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
LOGP(DLINP, LOGL_INFO, " tag %d: %s\n", data[1], str);
|
|
|
|
tag = msgb_put(nmsg, 3 + strlen(str) + 1);
|
|
|
|
tag[0] = 0x00;
|
|
|
|
tag[1] = 1 + strlen(str) + 1;
|
|
|
|
tag[2] = data[1];
|
|
|
|
memcpy(tag + 3, str, strlen(str) + 1);
|
|
|
|
data += 2;
|
|
|
|
len -= 2;
|
|
|
|
}
|
|
|
|
osmo_ipa_msg_push_header(nmsg, IPAC_PROTO_IPACCESS);
|
|
|
|
return nmsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct msgb *ipa_cli_id_ack(void)
|
|
|
|
{
|
|
|
|
struct msgb *nmsg2;
|
|
|
|
|
|
|
|
nmsg2 = osmo_ipa_msg_alloc(0);
|
|
|
|
if (nmsg2 == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*msgb_put(nmsg2, 1) = IPAC_MSGT_ID_ACK;
|
|
|
|
osmo_ipa_msg_push_header(nmsg2, IPAC_PROTO_IPACCESS);
|
|
|
|
|
|
|
|
return nmsg2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
abis_ipa_cli_rcvmsg(struct osmo_chan *c, struct osmo_stream_cli *conn,
|
|
|
|
struct msgb *msg, int type)
|
|
|
|
{
|
|
|
|
uint8_t msg_type = *(msg->l2h);
|
|
|
|
struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn);
|
|
|
|
struct chan_abis_ipa_cli *chan = (struct chan_abis_ipa_cli *)&c->data;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Handle IPA PING, PONG and ID_ACK messages. */
|
2012-08-15 22:31:40 +00:00
|
|
|
if (osmo_ipa_rcvmsg_base(msg, ofd, 0)) /* XXX: 0 indicates client */
|
2012-08-15 21:09:39 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (msg_type == IPAC_MSGT_ID_GET) {
|
|
|
|
struct msgb *rmsg;
|
|
|
|
uint8_t *data = msgb_l2(msg);
|
|
|
|
int len = msgb_l2len(msg);
|
|
|
|
|
|
|
|
LOGP(DLINP, LOGL_NOTICE, "received ID get\n");
|
|
|
|
|
|
|
|
rmsg = ipa_cli_id_resp(chan->unit, data + 1, len - 1);
|
|
|
|
osmo_stream_cli_send(conn, rmsg);
|
|
|
|
|
|
|
|
/* send ID_ACK. */
|
|
|
|
rmsg = ipa_cli_id_ack();
|
|
|
|
osmo_stream_cli_send(conn, rmsg);
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "Unknown IPA message type\n");
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_cb(struct osmo_stream_cli *conn, int type)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct msgb *msg;
|
|
|
|
struct osmo_fd *ofd = osmo_stream_cli_get_ofd(conn);
|
|
|
|
struct osmo_chan *chan = osmo_stream_cli_get_data(conn);
|
|
|
|
struct chan_abis_ipa_cli *s;
|
|
|
|
struct ipa_head *hh;
|
|
|
|
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "received message from stream\n");
|
|
|
|
|
|
|
|
msg = osmo_ipa_msg_alloc(0);
|
|
|
|
if (msg == NULL) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "cannot allocate message\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* XXX replace with generic stream reader */
|
|
|
|
ret = osmo_ipa_msg_recv(ofd->fd, msg);
|
|
|
|
if (ret < 0) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "cannot receive message\n");
|
|
|
|
msgb_free(msg);
|
|
|
|
/* not the dummy connection, release it. */
|
|
|
|
return 0;
|
|
|
|
} else if (ret == 0) {
|
|
|
|
/* link has vanished, dead socket. */
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "closed connection\n");
|
|
|
|
msgb_free(msg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
hh = (struct ipa_head *) msg->data;
|
|
|
|
if (hh->proto == IPAC_PROTO_IPACCESS) {
|
|
|
|
abis_ipa_cli_rcvmsg(chan, conn, msg, type);
|
|
|
|
msgb_free(msg);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
chan = osmo_stream_cli_get_data(conn);
|
|
|
|
if (chan == NULL) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "no matching signalling link\n");
|
|
|
|
msgb_free(msg);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
if (hh->proto != IPAC_PROTO_OML && hh->proto != IPAC_PROTO_RSL) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "wrong protocol\n");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
msg->dst = chan;
|
|
|
|
|
|
|
|
s = (struct chan_abis_ipa_cli *)chan->data;
|
|
|
|
s->signal_msg(msg, type);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int oml_read_cb(struct osmo_stream_cli *conn)
|
|
|
|
{
|
|
|
|
return read_cb(conn, CHAN_SIGN_OML);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rsl_read_cb(struct osmo_stream_cli *conn)
|
|
|
|
{
|
|
|
|
return read_cb(conn, CHAN_SIGN_RSL);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct osmo_chan_type chan_abis_ipa_cli = {
|
2012-08-18 22:31:35 +00:00
|
|
|
.type = OSMO_CHAN_ABIS_IPA_CLI,
|
2012-08-18 22:52:00 +00:00
|
|
|
.subtype = OSMO_SUBCHAN_STREAM,
|
2012-08-18 21:58:28 +00:00
|
|
|
.name = "A-bis IPA client",
|
2012-08-15 21:09:39 +00:00
|
|
|
.datasiz = sizeof(struct chan_abis_ipa_cli),
|
|
|
|
.create = chan_abis_ipa_cli_create,
|
|
|
|
.destroy = chan_abis_ipa_cli_destroy,
|
|
|
|
.open = chan_abis_ipa_cli_open,
|
|
|
|
.close = chan_abis_ipa_cli_close,
|
|
|
|
.enqueue = chan_abis_ipa_cli_enqueue,
|
|
|
|
};
|