summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso2011-06-30 12:19:42 +0200
committerPablo Neira Ayuso2011-06-30 12:19:42 +0200
commitc9c4fd39055ab02c0af59d5519e62edc456e3d0b (patch)
treeb4ddf50a9b715a7a0270077e21790e8ec5efaf59
parentipaccess: use E1INP_SIGN_OML instead of hardcoded 1 (diff)
downloadlibosmo-abis-c9c4fd39055ab02c0af59d5519e62edc456e3d0b.tar.gz
libosmo-abis-c9c4fd39055ab02c0af59d5519e62edc456e3d0b.tar.xz
libosmo-abis-c9c4fd39055ab02c0af59d5519e62edc456e3d0b.zip
major updates in e1_input callback ops and IPA infrastructures
This patch is a major update of the callback infrastructure, now the e1input_ops looks like the following: struct e1inp_sign_link * (*sign_link_up)(void *unit_info, struct e1inp_line *line, enum e1inp_sign_type type); void (*sign_link_down)(struct e1inp_line *line); int (*sign_link)(struct msgb *msg, struct e1inp_sign_link *link); The sign_link_up and sign_link_down will be used by the A-bis over IP input drivers. The sign_link_up callback is used if we receive a ID_RESP message, in that case, we have to set up the sign link for the corresponding new OML/RSL signal link. The pointer to unit_info provides a data structure that contains the BTS device details if we run as BSC, and the requested device information from the BSC if we run as BTS. The sign_link_up callback must return the new sign_link created. The sign_link_down callback is invoked if the line does down, which means that the counterpart has closed the socket. The sign_link callback is used to handle all RSL/OML messages. I have also added the following callback to the e1inp_driver: + void (*close)(struct e1inp_ts *ts); Which is invoked if you call e1inp_sign_link_destroy(). This callback is used to close the socket that is linked to that timeslot. This is useful for A-bis over IP drivers since sockets are closed if the OML/RSL signalling link is destroyed. As you can notice, I have also added all the ID_RESP parsing into libosmo-abis for both ipaccess and hsl drivers. This patch also contains a rework of the ipa_client_link whose integration with the e1_input infrastructure was broken (the transmission path was broken). This patch also contains more develop examples that act as BSC and BTS for the ipaccess driver. Sorry, I know it would be better to split all these changes into logical pieces but many of them are tightly related. This is under heavy development stage, it's anyway hard to track changes until this becomes more stable.
-rw-r--r--include/osmocom/abis/e1_input.h7
-rw-r--r--include/osmocom/abis/ipa.h9
-rw-r--r--include/osmocom/abis/ipaccess.h10
-rw-r--r--src/e1_input.c5
-rw-r--r--src/input/hsl.c79
-rw-r--r--src/input/ipa.c78
-rw-r--r--src/input/ipaccess.c300
-rw-r--r--src/input/misdn.c5
-rw-r--r--src/ipa_proxy.c6
-rw-r--r--tests/e1inp_ipa_bsc_test.c41
-rw-r--r--tests/e1inp_ipa_bts_test.c222
11 files changed, 611 insertions, 151 deletions
diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h
index a9b6178..d2033ef 100644
--- a/include/osmocom/abis/e1_input.h
+++ b/include/osmocom/abis/e1_input.h
@@ -116,6 +116,7 @@ struct e1inp_driver {
const char *name;
int (*want_write)(struct e1inp_ts *ts);
int (*line_update)(struct e1inp_line *line, enum e1inp_line_role role, const char *addr);
+ void (*close)(struct e1inp_ts *ts);
int default_delay;
};
@@ -123,9 +124,9 @@ struct e1inp_line_ops {
enum e1inp_line_role role;
char *addr;
- int (*sign_link_up)(struct msgb *msg, struct e1inp_line *line, enum e1inp_sign_type type);
- int (*sign_link)(struct msgb *msg, struct e1inp_line *line, struct e1inp_sign_link *link);
- int (*error)(struct msgb *msg, struct e1inp_line *line, enum e1inp_sign_type type, int error);
+ struct e1inp_sign_link * (*sign_link_up)(void *unit_info, struct e1inp_line *line, enum e1inp_sign_type type);
+ void (*sign_link_down)(struct e1inp_line *line);
+ int (*sign_link)(struct msgb *msg, struct e1inp_sign_link *link);
};
struct e1inp_line {
diff --git a/include/osmocom/abis/ipa.h b/include/osmocom/abis/ipa.h
index f088ec0..d455069 100644
--- a/include/osmocom/abis/ipa.h
+++ b/include/osmocom/abis/ipa.h
@@ -42,19 +42,22 @@ enum ipa_client_link_state {
struct ipa_client_link {
struct e1inp_line *line;
- struct osmo_fd ofd;
+ struct osmo_fd *ofd;
struct llist_head tx_queue;
struct osmo_timer_list timer;
enum ipa_client_link_state state;
const char *addr;
uint16_t port;
- int (*cb)(struct ipa_client_link *link, struct msgb *msg);
+ int (*read_cb)(struct ipa_client_link *link, struct msgb *msg);
+ int (*write_cb)(struct ipa_client_link *link);
void *data;
};
-struct ipa_client_link *ipa_client_link_create(void *ctx, struct e1inp_line *line, const char *addr, uint16_t port, int (*cb)(struct ipa_client_link *link, struct msgb *msgb), void *data);
+struct ipa_client_link *ipa_client_link_create(void *ctx, struct e1inp_ts *ts, const char *driver_name, int priv_nr, const char *addr, uint16_t port, int (*read_cb)(struct ipa_client_link *link, struct msgb *msgb), int (*write_cb)(struct ipa_client_link *link), void *data);
void ipa_client_link_destroy(struct ipa_client_link *link);
+int ipa_client_write_default_cb(struct ipa_client_link *link);
+
int ipa_client_link_open(struct ipa_client_link *link);
void ipa_client_link_close(struct ipa_client_link *link);
diff --git a/include/osmocom/abis/ipaccess.h b/include/osmocom/abis/ipaccess.h
index 2792572..d4174a8 100644
--- a/include/osmocom/abis/ipaccess.h
+++ b/include/osmocom/abis/ipaccess.h
@@ -90,4 +90,14 @@ struct sdp_header_entry {
uint32_t start;
} __attribute__((packed));
+struct ipaccess_unit {
+ uint16_t site_id;
+ uint16_t bts_id;
+ uint16_t trx_id;
+};
+
+struct hsl_unit {
+ unsigned long serno;
+};
+
#endif /* _OSMO_PROTO_IPACCESS_H */
diff --git a/src/e1_input.c b/src/e1_input.c
index 057633c..d11a3ce 100644
--- a/src/e1_input.c
+++ b/src/e1_input.c
@@ -428,6 +428,9 @@ void e1inp_sign_link_destroy(struct e1inp_sign_link *link)
if (link->ts->type == E1INP_TS_TYPE_SIGN)
osmo_timer_del(&link->ts->sign.tx_timer);
+ if (link->ts->line->driver->close)
+ link->ts->line->driver->close(link->ts);
+
talloc_free(link);
}
@@ -454,7 +457,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
"no action set for signalling messages.\n");
return -ENOENT;
}
- ts->line->ops->sign_link(msg, ts->line, link);
+ ts->line->ops->sign_link(msg, link);
break;
case E1INP_TS_TYPE_TRAU:
ret = subch_demux_in(&ts->trau.demux, msg->l2h, msgb_l2len(msg));
diff --git a/src/input/hsl.c b/src/input/hsl.c
index a9a9a78..dd9f17d 100644
--- a/src/input/hsl.c
+++ b/src/input/hsl.c
@@ -74,6 +74,47 @@ static struct hsl_e1_handle *e1h;
#define TS1_ALLOC_SIZE 900
+static void hsl_drop(struct e1inp_line *line, struct osmo_fd *bfd)
+{
+ line->ops->sign_link_down(line);
+}
+
+static int process_hsl_rsl(struct msgb *msg, struct e1inp_line *line)
+{
+ char serno_buf[16];
+ uint8_t serno_len;
+ struct hsl_unit unit_data;
+
+ switch (msg->l2h[1]) {
+ case 0x80:
+ /*, contains Serial Number + SW version */
+ if (msg->l2h[2] != 0xc0)
+ break;
+ serno_len = msg->l2h[3];
+ if (serno_len > sizeof(serno_buf)-1)
+ serno_len = sizeof(serno_buf)-1;
+ memcpy(serno_buf, msg->l2h+4, serno_len);
+ serno_buf[serno_len] = '\0';
+ unit_data.serno = strtoul(serno_buf, NULL, 10);
+
+ if (!line->ops->sign_link_up) {
+ LOGP(DINP, LOGL_ERROR, "Fix your application, "
+ "no action set if the signalling link "
+ "becomes ready\n");
+ return -EINVAL;
+ }
+ line->ops->sign_link_up(&unit_data, line, E1INP_SIGN_NONE);
+ msgb_free(msg);
+ return 1; /* == we have taken over the msg */
+ case 0x82:
+ /* FIXME: do something with BSSGP, i.e. forward it over
+ * NSIP to OsmoSGSN */
+ msgb_free(msg);
+ return 1;
+ }
+ return 0;
+}
+
static int handle_ts1_read(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
@@ -85,14 +126,11 @@ static int handle_ts1_read(struct osmo_fd *bfd)
int ret = 0, error;
error = ipa_msg_recv(bfd->fd, &msg);
- if (error <= 0) {
- if (e1i_ts->line->ops->error)
- e1i_ts->line->ops->error(NULL, line, ts_nr, error);
- if (error == 0) {
- osmo_fd_unregister(bfd);
- close(bfd->fd);
- bfd->fd = -1;
- }
+ if (error < 0)
+ return error;
+ else if (error == 0) {
+ hsl_drop(e1i_ts->line, bfd);
+ LOGP(DINP, LOGL_NOTICE, "Sign link vanished, dead socket\n");
return error;
}
DEBUGP(DMI, "RX %u: %s\n", ts_nr, osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
@@ -106,19 +144,10 @@ static int handle_ts1_read(struct osmo_fd *bfd)
/* HSL proprietary RSL extension */
if (hh->proto == 0 && (msg->l2h[0] == 0x81 || msg->l2h[0] == 0x80)) {
- if (!line->ops->sign_link_up) {
- LOGP(DINP, LOGL_ERROR, "Fix your application, no "
- "action set if the signalling link "
- "becomes ready.\n");
- return -EINVAL;
- }
- ret = line->ops->sign_link_up(msg, line, E1INP_SIGN_RSL);
- if (ret < 0) {
- /* FIXME: close connection */
- if (line->ops->error)
- line->ops->error(msg, line,
- E1INP_SIGN_RSL, -EBADMSG);
- return ret;
+ ret = process_hsl_rsl(msg, line);
+ if (ret < 0) {
+ hsl_drop(e1i_ts->line, bfd);
+ return ret;
} else if (ret == 1)
return 0;
/* else: continue... */
@@ -144,7 +173,7 @@ static int handle_ts1_read(struct osmo_fd *bfd)
"no action set for signalling messages.\n");
return -ENOENT;
}
- e1i_ts->line->ops->sign_link(msg, line, link);
+ e1i_ts->line->ops->sign_link(msg, link);
return ret;
}
@@ -338,8 +367,10 @@ static int hsl_line_update(struct e1inp_line *line,
LOGP(DINP, LOGL_NOTICE, "enabling hsl BTS mode\n");
- link = ipa_client_link_create(tall_hsl_ctx, line, addr,
- HSL_TCP_PORT, hsl_bts_process,
+ link = ipa_client_link_create(tall_hsl_ctx,
+ &line->ts[0], "hsl", 0,
+ addr, HSL_TCP_PORT,
+ hsl_bts_process, NULL,
NULL);
if (link == NULL) {
LOGP(DINP, LOGL_ERROR, "cannot create BTS link: %s\n",
diff --git a/src/input/ipa.c b/src/input/ipa.c
index 0cd2540..2d499ee 100644
--- a/src/input/ipa.c
+++ b/src/input/ipa.c
@@ -87,13 +87,13 @@ static void ipa_client_retry(struct ipa_client_link *link)
void ipa_client_link_close(struct ipa_client_link *link)
{
- osmo_fd_unregister(&link->ofd);
- close(link->ofd.fd);
+ osmo_fd_unregister(link->ofd);
+ close(link->ofd->fd);
}
static void ipa_client_read(struct ipa_client_link *link)
{
- struct osmo_fd *ofd = &link->ofd;
+ struct osmo_fd *ofd = link->ofd;
struct msgb *msg;
int ret;
@@ -113,13 +113,19 @@ static void ipa_client_read(struct ipa_client_link *link)
ipa_client_retry(link);
return;
}
- if (link->cb)
- link->cb(link, msg);
+ if (link->read_cb)
+ link->read_cb(link, msg);
}
static void ipa_client_write(struct ipa_client_link *link)
{
- struct osmo_fd *ofd = &link->ofd;
+ if (link->write_cb)
+ link->write_cb(link);
+}
+
+int ipa_client_write_default_cb(struct ipa_client_link *link)
+{
+ struct osmo_fd *ofd = link->ofd;
struct msgb *msg;
struct llist_head *lh;
int ret;
@@ -128,13 +134,13 @@ static void ipa_client_write(struct ipa_client_link *link)
if (llist_empty(&link->tx_queue)) {
ofd->when &= ~BSC_FD_WRITE;
- return;
+ return 0;
}
lh = link->tx_queue.next;
llist_del(lh);
msg = llist_entry(lh, struct msgb, list);
- ret = send(link->ofd.fd, msg->data, msg->len, 0);
+ ret = send(link->ofd->fd, msg->data, msg->len, 0);
if (ret < 0) {
if (errno == EPIPE || errno == ENOTCONN) {
ipa_client_retry(link);
@@ -142,6 +148,7 @@ static void ipa_client_write(struct ipa_client_link *link)
LOGP(DINP, LOGL_ERROR, "error to send\n");
}
msgb_free(msg);
+ return 0;
}
int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
@@ -162,11 +169,14 @@ int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
break;
case IPA_CLIENT_LINK_STATE_CONNECTED:
- LOGP(DINP, LOGL_NOTICE, "connected read/write\n");
- if (what & BSC_FD_READ)
+ if (what & BSC_FD_READ) {
+ LOGP(DINP, LOGL_NOTICE, "connected read\n");
ipa_client_read(link);
- if (what & BSC_FD_WRITE)
+ }
+ if (what & BSC_FD_WRITE) {
+ LOGP(DINP, LOGL_NOTICE, "connected write\n");
ipa_client_write(link);
+ }
break;
default:
break;
@@ -177,10 +187,12 @@ int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
static void ipa_link_timer_cb(void *data);
struct ipa_client_link *
-ipa_client_link_create(void *ctx, struct e1inp_line *line,
- const char *addr, uint16_t port,
- int (*cb)(struct ipa_client_link *link,
- struct msgb *msgb), void *data)
+ipa_client_link_create(void *ctx, struct e1inp_ts *ts, const char *driver_name,
+ int priv_nr, const char *addr, uint16_t port,
+ int (*read_cb)(struct ipa_client_link *link,
+ struct msgb *msgb),
+ int (*write_cb)(struct ipa_client_link *link),
+ void *data)
{
struct ipa_client_link *ipa_link;
@@ -188,16 +200,36 @@ ipa_client_link_create(void *ctx, struct e1inp_line *line,
if (!ipa_link)
return NULL;
- ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
- ipa_link->ofd.cb = ipa_client_fd_cb;
- ipa_link->ofd.data = ipa_link;
+ if (ts) {
+ struct e1inp_driver *driver;
+
+ driver = e1inp_driver_find(driver_name);
+ if (driver == NULL) {
+ talloc_free(ipa_link);
+ return NULL;
+ }
+ ts->line->driver = driver;
+ ipa_link->ofd = &ts->driver.ipaccess.fd;
+ } else {
+ ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
+ if (ipa_link->ofd == NULL) {
+ talloc_free(ipa_link);
+ return NULL;
+ }
+ }
+
+ ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
+ ipa_link->ofd->priv_nr = priv_nr;
+ ipa_link->ofd->cb = ipa_client_fd_cb;
+ ipa_link->ofd->data = ipa_link;
ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
ipa_link->timer.cb = ipa_link_timer_cb;
ipa_link->timer.data = ipa_link;
ipa_link->addr = talloc_strdup(ipa_link, addr);
ipa_link->port = port;
- ipa_link->cb = cb;
- ipa_link->line = line;
+ ipa_link->read_cb = read_cb;
+ ipa_link->write_cb = write_cb;
+ ipa_link->line = ts->line;
ipa_link->data = data;
INIT_LLIST_HEAD(&ipa_link->tx_queue);
@@ -220,8 +252,8 @@ int ipa_client_link_open(struct ipa_client_link *link)
if (errno != EINPROGRESS)
return ret;
}
- link->ofd.fd = ret;
- if (osmo_fd_register(&link->ofd) < 0) {
+ link->ofd->fd = ret;
+ if (osmo_fd_register(link->ofd) < 0) {
close(ret);
return -EIO;
}
@@ -246,7 +278,7 @@ static void ipa_link_timer_cb(void *data)
void ipa_client_link_send(struct ipa_client_link *link, struct msgb *msg)
{
msgb_enqueue(&link->tx_queue, msg);
- link->ofd.when |= BSC_FD_WRITE;
+ link->ofd->when |= BSC_FD_WRITE;
}
int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c
index 399ad45..74e2071 100644
--- a/src/input/ipaccess.c
+++ b/src/input/ipaccess.c
@@ -75,6 +75,91 @@ const uint8_t ipa_id_req_msg[] = {
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];
+}
+
+int ipaccess_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(DMI, LOGL_ERROR, "The tag does not fit: %d\n", t_len);
+ return -EINVAL;
+ }
+
+ DEBUGPC(DMI, "%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 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;
+ if (unit_data->site_id)
+ unit_data->site_id = ul & 0xffff;
+
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ if (unit_data->bts_id)
+ unit_data->bts_id = ul & 0xffff;
+
+ if (*endptr++ != '/')
+ return -EINVAL;
+
+ nptr = endptr;
+ ul = strtoul(nptr, &endptr, 10);
+ if (endptr <= nptr)
+ return -EINVAL;
+ if (unit_data->trx_id)
+ unit_data->trx_id = ul & 0xffff;
+
+ return 0;
+}
+
static int ipaccess_send(int fd, const void *msg, size_t msglen)
{
int ret;
@@ -126,10 +211,48 @@ int ipaccess_rcvmsg_base(struct msgb *msg,
return 0;
}
+/* base handling of the ip.access protocol */
+int ipaccess_rcvmsg_bts_base(struct msgb *msg,
+ struct osmo_fd *bfd)
+{
+ uint8_t msg_type = *(msg->l2h);
+ int ret = 0;
+
+ switch (msg_type) {
+ case IPAC_MSGT_PING:
+ ret = ipaccess_send_pong(bfd->fd);
+ break;
+ case IPAC_MSGT_PONG:
+ DEBUGP(DMI, "PONG!\n");
+ break;
+ case IPAC_MSGT_ID_ACK:
+ DEBUGP(DMI, "ID_ACK\n");
+ break;
+ }
+ return 0;
+}
+
+static void ipaccess_drop(struct osmo_fd *bfd)
+{
+ struct e1inp_line *line = bfd->data;
+
+ /* e1inp_sign_link_destroy releases the socket descriptors for us. */
+ line->ops->sign_link_down(line);
+
+ /* RSL connection without ID_RESP, release temporary socket. */
+ if (line->ts[E1INP_SIGN_OML-1].type == E1INP_SIGN_NONE)
+ talloc_free(bfd);
+}
+
static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
struct osmo_fd *bfd)
{
+ struct tlv_parsed tlvp;
uint8_t msg_type = *(msg->l2h);
+ struct ipaccess_unit unit_data = {};
+ struct e1inp_sign_link *sign_link;
+ char *unitid;
+ int len, ret;
/* handle base messages */
ipaccess_rcvmsg_base(msg, bfd);
@@ -137,13 +260,71 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
switch (msg_type) {
case IPAC_MSGT_ID_RESP:
DEBUGP(DMI, "ID_RESP\n");
+ /* parse tags, search for Unit ID */
+ ret = ipaccess_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2,
+ msgb_l2len(msg)-2);
+ DEBUGP(DMI, "\n");
+ if (ret < 0) {
+ LOGP(DINP, LOGL_ERROR, "ignoring IPA response message "
+ "with malformed TLVs\n");
+ return ret;
+ }
+ if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT))
+ break;
+
+ len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT);
+ if (len < 1)
+ break;
+
+ unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT);
+ unitid[len - 1] = '\0';
+ ipaccess_parse_unitid(unitid, &unit_data);
+
if (!line->ops->sign_link_up) {
LOGP(DINP, LOGL_ERROR, "Fix your application, "
"no action set if the signalling link "
"becomes ready\n");
return -EINVAL;
}
- line->ops->sign_link_up(msg, line, bfd->priv_nr);
+ /* the BSC creates the new sign links at this stage. */
+ if (bfd->priv_nr == E1INP_SIGN_OML) {
+ sign_link =
+ line->ops->sign_link_up(&unit_data, line,
+ E1INP_SIGN_OML);
+ if (sign_link == NULL) {
+ LOGP(DINP, LOGL_ERROR,
+ "No OML signal link set by BSC\n");
+ }
+ } else if (bfd->priv_nr == E1INP_SIGN_RSL) {
+ struct e1inp_ts *e1i_ts;
+ struct osmo_fd *newbfd;
+
+ sign_link =
+ line->ops->sign_link_up(&unit_data, line,
+ E1INP_SIGN_RSL);
+ if (sign_link == NULL) {
+ LOGP(DINP, LOGL_ERROR, "Don't know where "
+ "to attach this RSL link.\n");
+ osmo_fd_unregister(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+ talloc_free(bfd);
+ return 0;
+ }
+ /* Finally, we know which OML link is associated with
+ * this RSL link, attach it to this socket. */
+ bfd->data = line = sign_link->ts->line;
+ e1i_ts = &line->ts[E1INP_SIGN_RSL+unit_data.trx_id-1];
+ newbfd = &e1i_ts->driver.ipaccess.fd;
+
+ /* get rid of our old temporary bfd */
+ memcpy(newbfd, bfd, sizeof(*newbfd));
+ newbfd->priv_nr = E1INP_SIGN_RSL + unit_data.trx_id;
+ osmo_fd_unregister(bfd);
+ bfd->fd = -1;
+ talloc_free(bfd);
+ osmo_fd_register(newbfd);
+ }
break;
}
return 0;
@@ -160,16 +341,11 @@ static int handle_ts1_read(struct osmo_fd *bfd)
int ret = 0, error;
error = ipa_msg_recv(bfd->fd, &msg);
- if (error <= 0) {
- /* skip if RSL line is not set yet. */
- if (e1i_ts && e1i_ts->line->ops->error)
- e1i_ts->line->ops->error(NULL, line, ts_nr, error);
- if (error == 0) {
- osmo_fd_unregister(bfd);
- close(bfd->fd);
- bfd->fd = -1;
- talloc_free(bfd);
- }
+ if (error < 0)
+ return error;
+ else if (error == 0) {
+ ipaccess_drop(bfd);
+ LOGP(DINP, LOGL_NOTICE, "Sign link vanished, dead socket\n");
return error;
}
DEBUGP(DMI, "RX %u: %s\n", ts_nr, osmo_hexdump(msgb_l2(msg), msgb_l2len(msg)));
@@ -202,7 +378,7 @@ static int handle_ts1_read(struct osmo_fd *bfd)
"no action set for signalling messages.\n");
return -ENOENT;
}
- e1i_ts->line->ops->sign_link(msg, line, link);
+ e1i_ts->line->ops->sign_link(msg, link);
return ret;
}
@@ -233,6 +409,14 @@ static int ts_want_write(struct e1inp_ts *e1i_ts)
return 0;
}
+static void ipaccess_close(struct e1inp_ts *e1i_ts)
+{
+ struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd;
+ osmo_fd_unregister(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+}
+
static void timeout_ts1_write(void *data)
{
struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
@@ -241,9 +425,8 @@ static void timeout_ts1_write(void *data)
ts_want_write(e1i_ts);
}
-static int handle_ts1_write(struct osmo_fd *bfd)
+static int __handle_ts1_write(struct osmo_fd *bfd, struct e1inp_line *line)
{
- struct e1inp_line *line = bfd->data;
unsigned int ts_nr = bfd->priv_nr;
struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
struct e1inp_sign_link *sign_link;
@@ -274,7 +457,9 @@ static int handle_ts1_write(struct osmo_fd *bfd)
}
msg->l2h = msg->data;
- ipaccess_prepend_header(msg, sign_link->tei);
+ /* This is an IPA CCM, it already contains the header, skip. */
+ if (msgb_tailroom(msg) < sizeof(struct ipaccess_head))
+ ipaccess_prepend_header(msg, sign_link->tei);
DEBUGP(DMI, "TX %u: %s\n", ts_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
@@ -291,27 +476,29 @@ static int handle_ts1_write(struct osmo_fd *bfd)
return ret;
}
-/* callback from select.c in case one of the fd's can be read/written */
-static int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what)
+int handle_ts1_write(struct osmo_fd *bfd)
{
struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- unsigned int idx = ts_nr-1;
- struct e1inp_ts *e1i_ts;
- int rc = 0;
- /* In case of early RSL we might not yet have a line */
+ return __handle_ts1_write(bfd, line);
+}
+
+int ipaccess_bts_write_cb(struct ipa_client_link *link)
+{
+ struct e1inp_line *line = link->line;
+
+ return __handle_ts1_write(link->ofd, line);
+}
- if (line)
- e1i_ts = &line->ts[idx];
+/* callback from select.c in case one of the fd's can be read/written */
+static int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what)
+{
+ int rc = 0;
- if (!line || e1i_ts->type == E1INP_TS_TYPE_SIGN) {
- if (what & BSC_FD_READ)
- rc = handle_ts1_read(bfd);
- if (what & BSC_FD_WRITE)
- rc = handle_ts1_write(bfd);
- } else
- LOGP(DINP, LOGL_ERROR, "unknown E1 TS type %u\n", e1i_ts->type);
+ if (what & BSC_FD_READ)
+ rc = handle_ts1_read(bfd);
+ if (what & BSC_FD_WRITE)
+ rc = handle_ts1_write(bfd);
return rc;
}
@@ -323,6 +510,7 @@ struct e1inp_driver ipaccess_driver = {
.name = "ipa",
.want_write = ts_want_write,
.line_update = ipaccess_line_update,
+ .close = ipaccess_close,
.default_delay = 0,
};
@@ -332,10 +520,18 @@ static int ipaccess_bsc_oml_cb(struct ipa_server_link *link, int fd)
int ret;
int idx = 0;
int i;
- struct e1inp_line *line = link->line;
+ struct e1inp_line *line;
struct e1inp_ts *e1i_ts;
struct osmo_fd *bfd;
+ /* clone virtual E1 line for this new OML link. */
+ line = talloc_zero(tall_ipa_ctx, struct e1inp_line);
+ if (line == NULL) {
+ LOGP(DINP, LOGL_ERROR, "could not clone E1 line\n");
+ return -1;
+ }
+ memcpy(line, link->line, sizeof(struct e1inp_line));
+
/* create virrtual E1 timeslots for signalling */
e1inp_ts_config_sign(&line->ts[E1INP_SIGN_OML-1], line);
@@ -367,18 +563,17 @@ static int ipaccess_bsc_oml_cb(struct ipa_server_link *link, int fd)
static int ipaccess_bsc_rsl_cb(struct ipa_server_link *link, int fd)
{
struct osmo_fd *bfd;
- struct e1inp_line *line = link->line;
int ret;
- /* create virtual E1 timeslots for signalling */
- e1inp_ts_config_sign(&line->ts[E1INP_SIGN_RSL-1], line);
-
+ /* We don't know yet which OML link to associate it with. Thus, we
+ * allocate a temporary bfd until we have received ID. */
bfd = talloc_zero(tall_ipa_ctx, struct osmo_fd);
if (!bfd)
return -ENOMEM;
bfd->fd = fd;
- bfd->data = line;
+ /* This dummy line is replaced once we can attach it to the OML link */
+ bfd->data = link->line;
bfd->priv_nr = E1INP_SIGN_RSL;
bfd->cb = ipaccess_fd_cb;
bfd->when = BSC_FD_READ;
@@ -406,7 +601,7 @@ static int ipaccess_bts_cb(struct ipa_client_link *link, struct msgb *msg)
uint8_t msg_type = *(msg->l2h);
/* ping, pong and acknowledgment cases. */
- ipaccess_rcvmsg_base(msg, &link->ofd);
+ ipaccess_rcvmsg_bts_base(msg, link->ofd);
/* this is a request for identification from the BSC. */
if (msg_type == IPAC_MSGT_ID_GET) {
@@ -417,9 +612,14 @@ static int ipaccess_bts_cb(struct ipa_client_link *link, struct msgb *msg)
"becomes ready\n");
return -EINVAL;
}
- link->line->ops->sign_link_up(msg, link->line,
- link->port == IPA_TCP_PORT_OML ?
- E1INP_SIGN_OML : E1INP_SIGN_RSL);
+ /*
+ * FIXME: parse request here and pass data to callback.
+ */
+ struct e1inp_sign_link *sign_link;
+
+ sign_link = link->line->ops->sign_link_up(msg,
+ link->line,
+ link->ofd->priv_nr);
}
return 0;
} else if (link->port == IPA_TCP_PORT_OML)
@@ -444,7 +644,7 @@ static int ipaccess_bts_cb(struct ipa_client_link *link, struct msgb *msg)
"no action set for signalling messages.\n");
return -ENOENT;
}
- link->line->ops->sign_link(msg, link->line, sign_link);
+ link->line->ops->sign_link(msg, sign_link);
return 0;
}
@@ -497,9 +697,13 @@ static int ipaccess_line_update(struct e1inp_line *line,
LOGP(DINP, LOGL_NOTICE, "enabling ipaccess BTS mode\n");
- link = ipa_client_link_create(tall_ipa_ctx, line,
+ link = ipa_client_link_create(tall_ipa_ctx,
+ &line->ts[E1INP_SIGN_OML-1],
+ "ipa", E1INP_SIGN_OML,
addr, IPA_TCP_PORT_OML,
- ipaccess_bts_cb, NULL);
+ ipaccess_bts_cb,
+ ipaccess_bts_write_cb,
+ NULL);
if (link == NULL) {
LOGP(DINP, LOGL_ERROR, "cannot create OML "
"BTS link: %s\n", strerror(errno));
@@ -512,9 +716,13 @@ static int ipaccess_line_update(struct e1inp_line *line,
ipa_client_link_destroy(link);
return -EIO;
}
- rsl_link = ipa_client_link_create(tall_ipa_ctx, line,
+ rsl_link = ipa_client_link_create(tall_ipa_ctx,
+ &line->ts[E1INP_SIGN_RSL-1],
+ "ipa", E1INP_SIGN_RSL,
addr, IPA_TCP_PORT_RSL,
- ipaccess_bts_cb, NULL);
+ ipaccess_bts_cb,
+ ipaccess_bts_write_cb,
+ NULL);
if (rsl_link == NULL) {
LOGP(DINP, LOGL_ERROR, "cannot create RSL "
"BTS link: %s\n", strerror(errno));
diff --git a/src/input/misdn.c b/src/input/misdn.c
index cf8b5d9..9bf3aea 100644
--- a/src/input/misdn.c
+++ b/src/input/misdn.c
@@ -109,8 +109,7 @@ static int handle_ts1_read(struct osmo_fd *bfd)
}
if (alen != sizeof(l2addr)) {
- if (line->ops->error)
- line->ops->error(NULL, line, ts_nr, -EBADMSG);
+ fprintf(stderr, "%s error len\n", __func__);
return -EINVAL;
}
@@ -173,8 +172,6 @@ static int handle_ts1_read(struct osmo_fd *bfd)
l2addr.channel, l2addr.sapi, l2addr.tei);
break;
default:
- if (line->ops->error)
- line->ops->error(NULL, line, ts_nr, -EBADMSG);
break;
}
return ret;
diff --git a/src/ipa_proxy.c b/src/ipa_proxy.c
index 980e3c7..4d08e17 100644
--- a/src/ipa_proxy.c
+++ b/src/ipa_proxy.c
@@ -186,10 +186,12 @@ ipa_sock_src_accept_cb(struct ipa_server_link *link, int fd)
LOGP(DINP, LOGL_NOTICE, "now trying to connect to destination\n");
- conn->dst = ipa_client_link_create(NULL, NULL,
+ conn->dst = ipa_client_link_create(NULL, NULL, NULL, 0,
route->shared->dst.inst->net.addr,
route->shared->dst.inst->net.port,
- ipa_sock_dst_cb, conn);
+ ipa_sock_dst_cb,
+ ipa_client_write_default_cb,
+ conn);
if (conn->dst == NULL) {
LOGP(DINP, LOGL_ERROR, "could not create client: %s\n",
strerror(errno));
diff --git a/tests/e1inp_ipa_bsc_test.c b/tests/e1inp_ipa_bsc_test.c
index 64623b2..bac9926 100644
--- a/tests/e1inp_ipa_bsc_test.c
+++ b/tests/e1inp_ipa_bsc_test.c
@@ -6,25 +6,42 @@
#include <osmocom/core/logging.h>
static void *tall_test;
+static struct e1inp_sign_link *oml_sign_link, *rsl_sign_link;
-static int sign_link_up(struct msgb *msg, struct e1inp_line *line,
- enum e1inp_sign_type type)
+static struct e1inp_sign_link *
+sign_link_up(void *dev, struct e1inp_line *line, enum e1inp_sign_type type)
{
- printf("ID_RESP received, create sign link.\n");
- return 0;
+ struct e1inp_sign_link *sign_link = NULL;
+
+ switch(type) {
+ case E1INP_SIGN_OML:
+ e1inp_ts_config_sign(&line->ts[E1INP_SIGN_OML - 1], line);
+ sign_link = oml_sign_link =
+ e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML - 1],
+ E1INP_SIGN_OML, NULL, 255, 0);
+ break;
+ case E1INP_SIGN_RSL:
+ e1inp_ts_config_sign(&line->ts[E1INP_SIGN_RSL - 1], line);
+ sign_link = rsl_sign_link =
+ e1inp_sign_link_create(&line->ts[E1INP_SIGN_RSL - 1],
+ E1INP_SIGN_OML, NULL, 0, 0);
+ break;
+ default:
+ break;
+ }
+ return sign_link;
}
-static int sign_link(struct msgb *msg, struct e1inp_line *line,
- struct e1inp_sign_link *link)
+static void sign_link_down(struct e1inp_line *line)
{
- printf("OML/RSL data received\n");
- return 0;
+ printf("link got down.\n");
+ e1inp_sign_link_destroy(oml_sign_link);
+ e1inp_sign_link_destroy(rsl_sign_link);
}
-static int error(struct msgb *msg, struct e1inp_line *line,
- enum e1inp_sign_type type, int error)
+static int sign_link(struct msgb *msg, struct e1inp_sign_link *link)
{
- printf("error, malformed message\n");
+ printf("OML/RSL data received\n");
return 0;
}
@@ -58,8 +75,8 @@ int main(void)
.addr = "0.0.0.0",
.role = E1INP_LINE_R_BSC,
.sign_link_up = sign_link_up,
+ .sign_link_down = sign_link_down,
.sign_link = sign_link,
- .error = error,
};
#define LINENR 0
diff --git a/tests/e1inp_ipa_bts_test.c b/tests/e1inp_ipa_bts_test.c
index 9c6bd4c..643e898 100644
--- a/tests/e1inp_ipa_bts_test.c
+++ b/tests/e1inp_ipa_bts_test.c
@@ -1,32 +1,14 @@
#include <stdio.h>
#include <talloc.h>
+#include <string.h>
#include <osmocom/abis/abis.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/application.h>
+#include <osmocom/abis/ipaccess.h>
static void *tall_test;
-
-static int sign_link_up(struct msgb *msg, struct e1inp_line *line,
- enum e1inp_sign_type type)
-{
- printf("ID_RESP received, create sign link.\n");
- return 0;
-}
-
-static int sign_link(struct msgb *msg, struct e1inp_line *line,
- struct e1inp_sign_link *link)
-{
- printf("OML/RSL data received\n");
- return 0;
-}
-
-static int error(struct msgb *msg, struct e1inp_line *line,
- enum e1inp_sign_type type, int error)
-{
- printf("error, malformed message\n");
- return 0;
-}
+static struct e1inp_sign_link *oml_sign_link, *rsl_sign_link;
#define DBTSTEST OSMO_LOG_SS_APPS
@@ -45,6 +27,191 @@ const struct log_info bts_test_log_info = {
.num_cat = ARRAY_SIZE(bts_test_cat),
};
+struct dummy_bts {
+ uint16_t bts_id;
+ uint16_t site_id;
+ uint16_t trx_id;
+ uint8_t mac_addr[6];
+} dummy_bts = {
+ .site_id = 0,
+ .bts_id = 0,
+ .trx_id = 0,
+ .mac_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+};
+
+char *software_version = "0.1";
+
+static struct msgb *abis_msgb_alloc(int headroom)
+{
+ struct msgb *nmsg;
+
+ headroom += sizeof(struct ipaccess_head);
+
+ nmsg = msgb_alloc_headroom(1200 + headroom, headroom, "dummy BTS");
+ if (!nmsg)
+ return NULL;
+ return nmsg;
+}
+
+static void abis_push_ipa(struct msgb *msg, uint8_t proto)
+{
+ struct ipaccess_head *nhh;
+
+ msg->l2h = msg->data;
+ nhh = (struct ipaccess_head *) msgb_push(msg, sizeof(*nhh));
+ nhh->proto = proto;
+ nhh->len = htons(msgb_l2len(msg));
+}
+
+/* XXX: we have to do this in input/ipaccess.c, moreover we have to put this
+ * information in some data structure that we'll pass to sign_link_up. */
+static struct msgb *ipa_bts_id_resp(uint8_t *data, int len)
+{
+ struct msgb *nmsg;
+ char str[64];
+ uint8_t *tag;
+
+ nmsg = abis_msgb_alloc(0);
+ if (!nmsg)
+ return NULL;
+
+ *msgb_put(nmsg, 1) = IPAC_MSGT_ID_RESP;
+ while (len) {
+ if (len < 2) {
+ LOGP(DBTSTEST, LOGL_NOTICE,
+ "Short read of ipaccess tag\n");
+ msgb_free(nmsg);
+ return NULL;
+ }
+ switch (data[1]) {
+ case IPAC_IDTAG_UNIT:
+ sprintf(str, "%u/%u/%u",
+ dummy_bts.site_id,
+ dummy_bts.bts_id,
+ dummy_bts.trx_id);
+ break;
+ case IPAC_IDTAG_MACADDR:
+ sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+ dummy_bts.mac_addr[0], dummy_bts.mac_addr[1],
+ dummy_bts.mac_addr[2], dummy_bts.mac_addr[3],
+ dummy_bts.mac_addr[4], dummy_bts.mac_addr[5]);
+ break;
+ case IPAC_IDTAG_LOCATION1:
+ strcpy(str, "osmoBTS");
+ break;
+ case IPAC_IDTAG_LOCATION2:
+ strcpy(str, "osmoBTS");
+ break;
+ case IPAC_IDTAG_EQUIPVERS:
+ case IPAC_IDTAG_SWVERSION:
+ strcpy(str, software_version);
+ break;
+ case IPAC_IDTAG_UNITNAME:
+ sprintf(str, "osmoBTS-%02x-%02x-%02x-%02x-%02x-%02x",
+ dummy_bts.mac_addr[0], dummy_bts.mac_addr[1],
+ dummy_bts.mac_addr[2], dummy_bts.mac_addr[3],
+ dummy_bts.mac_addr[4], dummy_bts.mac_addr[5]);
+ break;
+ case IPAC_IDTAG_SERNR:
+ strcpy(str, "");
+ break;
+ default:
+ LOGP(DBTSTEST, LOGL_NOTICE,
+ "Unknown ipaccess tag 0x%02x\n", *data);
+ msgb_free(nmsg);
+ return NULL;
+ }
+ LOGP(DBTSTEST, 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;
+ }
+ abis_push_ipa(nmsg, IPAC_PROTO_IPACCESS);
+ return nmsg;
+}
+
+static struct msgb *ipa_bts_id_ack(void)
+{
+ struct msgb *nmsg2;
+
+ nmsg2 = abis_msgb_alloc(0);
+ if (!nmsg2)
+ return NULL;
+
+ *msgb_put(nmsg2, 1) = IPAC_MSGT_ID_ACK;
+ abis_push_ipa(nmsg2, IPAC_PROTO_IPACCESS);
+
+ return nmsg2;
+}
+
+static struct e1inp_sign_link *
+sign_link_up(void *unit, struct e1inp_line *line, enum e1inp_sign_type type)
+{
+ struct msgb *msg = unit;
+ struct msgb *rmsg;
+ uint8_t *data = msgb_l2(msg);
+ int len = msgb_l2len(msg);
+ struct e1inp_sign_link *sign_link = NULL;
+ void *dst = NULL;
+
+ switch(type) {
+ case E1INP_SIGN_OML:
+ printf("ID_RESP for OML received.\n");
+
+ e1inp_ts_config_sign(&line->ts[E1INP_SIGN_OML - 1], line);
+ sign_link = oml_sign_link =
+ e1inp_sign_link_create(&line->ts[E1INP_SIGN_OML - 1],
+ E1INP_SIGN_OML, NULL, 255, 0);
+ if (!oml_sign_link)
+ printf("cannot create OML sign link\n");
+
+ dst = oml_sign_link;
+ break;
+ case E1INP_SIGN_RSL:
+ printf("ID_RESP for RSL received.\n");
+
+ e1inp_ts_config_sign(&line->ts[E1INP_SIGN_RSL - 1], line);
+
+ sign_link = rsl_sign_link =
+ e1inp_sign_link_create(&line->ts[E1INP_SIGN_RSL - 1],
+ E1INP_SIGN_RSL, NULL, 0, 0);
+ if (!rsl_sign_link)
+ printf("cannot create RSL sign link\n");
+
+ dst = rsl_sign_link;
+ break;
+ default:
+ return NULL;
+ }
+
+ /* send ID_RESP. */
+ rmsg = ipa_bts_id_resp(data + 1, len - 1);
+ rmsg->dst = dst;
+ abis_sendmsg(rmsg);
+
+ /* send ID_ACK. */
+ rmsg = ipa_bts_id_ack();
+ rmsg->dst = dst;
+ abis_sendmsg(rmsg);
+
+ return sign_link;
+}
+
+static void sign_link_down(struct e1inp_line *line)
+{
+ printf("closing sign link.\n");
+}
+
+static int sign_link(struct msgb *msg, struct e1inp_sign_link *link)
+{
+ printf("OML/RSL data received\n");
+ return 0;
+}
+
int main(void)
{
struct e1inp_line *line;
@@ -58,8 +225,8 @@ int main(void)
.role = E1INP_LINE_R_BTS,
.addr = "127.0.0.1",
.sign_link_up = sign_link_up,
+ .sign_link_down = sign_link_down,
.sign_link = sign_link,
- .error = error,
};
#define LINENR 0
@@ -71,17 +238,6 @@ int main(void)
}
e1inp_line_bind_ops(line, &ops);
- /*
- * Depending if this is a real or virtual E1 lines:
- * - real (ISDN): create signal link for OML and RSL before line up.
- * - vitual (INET): we create it in signal_link_up(...) callback.
- *
- * The signal link is created via e1inp_sign_link_create(...)
- *
- * See e1_reconfig_trx and e1_reconfig_bts in libbsc/e1_config.c,
- * it explains how this is done with ISDN.
- */
-
if (e1inp_line_update(line) < 0) {
LOGP(DBTSTEST, LOGL_ERROR, "problem enabling E1 line\n");
exit(EXIT_FAILURE);