diff options
author | Harald Welte <laforge@gnumonks.org> | 2014-08-20 22:04:11 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2014-08-20 23:41:07 +0200 |
commit | b65f58f6f9e504a017e83634e1cceebdd7525fdb (patch) | |
tree | 47853fc50e66c59a39d4dac8188641468dd51610 | |
parent | ipa: Add E1INP_SIGN_OSMO to use IPAC_PROTO_OSMO via e1_input (diff) | |
download | libosmo-abis-b65f58f6f9e504a017e83634e1cceebdd7525fdb.tar.xz libosmo-abis-b65f58f6f9e504a017e83634e1cceebdd7525fdb.zip |
move various generic IPA related functions to libosmocore
libosmo-abis is about forming A-bis interfaces/lines by means
of E1 or the IPA multiplex (or possibly other link layers).
The IPA multiplex is used in other contexts, such as the Control
interface, or the A interface. In that context, it makes sense to have
generic IPA related functions in libosmocore.
-rw-r--r-- | include/osmocom/abis/ipa.h | 15 | ||||
-rw-r--r-- | include/osmocom/abis/ipaccess.h | 13 | ||||
-rw-r--r-- | src/input/ipa.c | 143 | ||||
-rw-r--r-- | src/input/ipaccess.c | 286 | ||||
-rw-r--r-- | tests/e1inp_ipa_bts_test.c | 1 |
5 files changed, 13 insertions, 445 deletions
diff --git a/include/osmocom/abis/ipa.h b/include/osmocom/abis/ipa.h index 17b5f23..19815f6 100644 --- a/include/osmocom/abis/ipa.h +++ b/include/osmocom/abis/ipa.h @@ -4,7 +4,7 @@ #include <stdint.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/timer.h> -#include <osmocom/abis/ipaccess.h> +#include <osmocom/gsm/ipa.h> struct ipa_server_link { struct e1inp_line *line; @@ -80,22 +80,9 @@ void ipa_client_conn_close(struct ipa_client_conn *link); void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg); -int ipa_msg_recv(int fd, struct msgb **rmsg); -int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg); - -int ipaccess_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd); int ipaccess_bts_handle_ccm(struct ipa_client_conn *link, struct ipaccess_unit *dev, struct msgb *msg); -void ipaccess_prepend_header(struct msgb *msg, int proto); -void ipaccess_prepend_header_ext(struct msgb *msg, int proto); - void ipa_msg_push_header(struct msgb *msg, uint8_t proto); -int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len); -int ipaccess_send_id_req(int fd); -int ipaccess_parse_unitid(const char *str, struct ipaccess_unit *unit_data); -int ipaccess_tlv_to_unitdata(struct ipaccess_unit *ud, - const struct tlv_parsed *tp); - #endif diff --git a/include/osmocom/abis/ipaccess.h b/include/osmocom/abis/ipaccess.h index 1992807..b1fe2c9 100644 --- a/include/osmocom/abis/ipaccess.h +++ b/include/osmocom/abis/ipaccess.h @@ -4,19 +4,6 @@ #include <stdint.h> #include <osmocom/gsm/protocol/ipaccess.h> -struct ipaccess_unit { - uint16_t site_id; - uint16_t bts_id; - uint16_t trx_id; - char *unit_name; - char *equipvers; - char *swversion; - uint8_t mac_addr[6]; - char *location1; - char *location2; - char *serno; -}; - /* quick solution to get openBSC's ipaccess tools working. */ extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what); diff --git a/src/input/ipa.c b/src/input/ipa.c index e7ae6fb..e2da6f4 100644 --- a/src/input/ipa.c +++ b/src/input/ipa.c @@ -23,20 +23,6 @@ #include <osmocom/abis/ipa.h> -#define IPA_ALLOC_SIZE 1200 - -struct msgb *ipa_msg_alloc(int headroom) -{ - struct msgb *nmsg; - - headroom += sizeof(struct ipaccess_head); - - nmsg = msgb_alloc_headroom(1200 + headroom, headroom, "Abis/IP"); - if (!nmsg) - return NULL; - return nmsg; -} - void ipa_msg_push_header(struct msgb *msg, uint8_t proto) { struct ipaccess_head *hh; @@ -47,135 +33,6 @@ void ipa_msg_push_header(struct msgb *msg, uint8_t proto) hh->len = htons(msgb_l2len(msg)); } -int ipa_msg_recv(int fd, struct msgb **rmsg) -{ - int rc = ipa_msg_recv_buffered(fd, rmsg, NULL); - if (rc < 0) { - errno = -rc; - rc = -1; - } - return rc; -} - -int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg) -{ - struct msgb *msg = tmp_msg ? *tmp_msg : NULL; - struct ipaccess_head *hh; - int len, ret; - int needed; - - if (msg == NULL) { - msg = ipa_msg_alloc(0); - if (msg == NULL) { - ret = -ENOMEM; - goto discard_msg; - } - msg->l1h = msg->tail; - } - - if (msg->l2h == NULL) { - /* first read our 3-byte header */ - needed = sizeof(*hh) - msg->len; - ret = recv(fd, msg->tail, needed, 0); - if (ret == 0) - goto discard_msg; - - if (ret < 0) { - if (errno == EAGAIN || errno == EINTR) - ret = 0; - else { - ret = -errno; - goto discard_msg; - } - } - - msgb_put(msg, ret); - - if (ret < needed) { - if (msg->len == 0) { - ret = -EAGAIN; - goto discard_msg; - } - - LOGP(DLINP, LOGL_INFO, - "Received part of IPA message header (%d/%d)\n", - msg->len, sizeof(*hh)); - if (!tmp_msg) { - ret = -EIO; - goto discard_msg; - } - *tmp_msg = msg; - return -EAGAIN; - } - - msg->l2h = msg->tail; - } - - hh = (struct ipaccess_head *) msg->data; - - /* then read the length as specified in header */ - len = ntohs(hh->len); - - if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) { - LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, " - "received %d bytes\n", len, msg->len); - ret = -EIO; - goto discard_msg; - } - - needed = len - msgb_l2len(msg); - - if (needed > 0) { - ret = recv(fd, msg->tail, needed, 0); - - if (ret == 0) - goto discard_msg; - - if (ret < 0) { - if (errno == EAGAIN || errno == EINTR) - ret = 0; - else { - ret = -errno; - goto discard_msg; - } - } - - msgb_put(msg, ret); - - if (ret < needed) { - LOGP(DLINP, LOGL_INFO, - "Received part of IPA message L2 data (%d/%d)\n", - msgb_l2len(msg), len); - if (!tmp_msg) { - ret = -EIO; - goto discard_msg; - } - *tmp_msg = msg; - return -EAGAIN; - } - } - - ret = msgb_l2len(msg); - - if (ret == 0) { - LOGP(DLINP, LOGL_INFO, - "Discarding IPA message without payload\n"); - ret = -EAGAIN; - goto discard_msg; - } - - if (tmp_msg) - *tmp_msg = NULL; - *rmsg = msg; - return ret; - -discard_msg: - if (tmp_msg) - *tmp_msg = NULL; - msgb_free(msg); - return ret; -} - void ipa_client_conn_close(struct ipa_client_conn *link) { /* be safe against multiple calls */ diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 8ae00d3..b8932a2 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -47,6 +47,7 @@ #include <osmocom/core/socket.h> #include <osmocom/abis/ipa.h> #include <osmocom/core/backtrace.h> +#include <osmocom/gsm/ipa.h> static void *tall_ipa_ctx; @@ -56,250 +57,6 @@ static void *tall_ipa_ctx; #define DEFAULT_TCP_KEEPALIVE_INTERVAL 3 #define DEFAULT_TCP_KEEPALIVE_RETRY_COUNT 10 -/* - * 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. - */ -static const uint8_t ipa_pong_msg[] = { - 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG -}; - -static const uint8_t ipa_id_ack_msg[] = { - 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK -}; - -static 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]; -} - -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(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 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; -} - -int ipaccess_tlv_to_unitdata(struct ipaccess_unit *ud, - const struct tlv_parsed *tp) -{ - int rc = 0; - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SERNR, 1)) - ud->serno = talloc_strdup(ud, (char *) - TLVP_VAL(tp, IPAC_IDTAG_SERNR)); - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNITNAME, 1)) - ud->unit_name = talloc_strdup(ud, (char *) - TLVP_VAL(tp, IPAC_IDTAG_UNITNAME)); - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION1, 1)) - ud->location1 = talloc_strdup(ud, (char *) - TLVP_VAL(tp, IPAC_IDTAG_LOCATION1)); - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_LOCATION2, 1)) - ud->location2 = talloc_strdup(ud, (char *) - TLVP_VAL(tp, IPAC_IDTAG_LOCATION2)); - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_EQUIPVERS, 1)) - ud->equipvers = talloc_strdup(ud, (char *) - TLVP_VAL(tp, IPAC_IDTAG_EQUIPVERS)); - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_SWVERSION, 1)) - ud->swversion = talloc_strdup(ud, (char *) - TLVP_VAL(tp, IPAC_IDTAG_SWVERSION)); - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_MACADDR, 17)) { - rc = osmo_macaddr_parse(ud->mac_addr, (char *) - TLVP_VAL(tp, IPAC_IDTAG_MACADDR)); - if (rc < 0) - goto out; - } - - if (TLVP_PRES_LEN(tp, IPAC_IDTAG_UNIT, 1)) - rc = ipaccess_parse_unitid((char *) - TLVP_VAL(tp, IPAC_IDTAG_UNIT), ud); - -out: - return rc; -} - -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 ipaccess_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd) -{ - uint8_t msg_type = *(msg->l2h); - int ret; - - switch (msg_type) { - case IPAC_MSGT_PING: - ret = ipaccess_send_pong(bfd->fd); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Cannot send PING " - "message. Reason: %s\n", strerror(errno)); - break; - } - ret = 1; - break; - case IPAC_MSGT_PONG: - DEBUGP(DLMI, "PONG!\n"); - ret = 1; - break; - case IPAC_MSGT_ID_ACK: - DEBUGP(DLMI, "ID_ACK? -> ACK!\n"); - ret = ipaccess_send_id_ack(bfd->fd); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Cannot send ID_ACK " - "message. Reason: %s\n", strerror(errno)); - break; - } - ret = 1; - break; - default: - /* This is not an IPA PING, PONG or ID_ACK message */ - ret = 0; - break; - } - return ret; -} - -/* 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); - if (ret < 0) { - LOGP(DLINP, LOGL_ERROR, "Cannot send PONG " - "message. Reason: %s\n", strerror(errno)); - } - break; - case IPAC_MSGT_PONG: - DEBUGP(DLMI, "PONG!\n"); - break; - case IPAC_MSGT_ID_ACK: - DEBUGP(DLMI, "ID_ACK\n"); - break; - } - return ret; -} - static int ipaccess_drop(struct osmo_fd *bfd, struct e1inp_line *line) { int ret = 1; @@ -336,7 +93,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, int len, ret; /* Handle IPA PING, PONG and ID_ACK messages. */ - ret = ipaccess_rcvmsg_base(msg, bfd); + ret = ipa_ccm_rcvmsg_base(msg, bfd); switch(ret) { case -1: /* error in IPA control message handling */ @@ -349,7 +106,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, break; default: LOGP(DLINP, LOGL_ERROR, "Unexpected return from " - "ipaccess_rcvmsg_base " + "ipa_ccm_rcvmsg_base " "(ret=%d)\n", ret); goto err; } @@ -358,7 +115,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, case IPAC_MSGT_ID_RESP: DEBUGP(DLMI, "ID_RESP\n"); /* parse tags, search for Unit ID */ - ret = ipaccess_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2, + ret = ipa_ccm_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2, msgb_l2len(msg)-2); DEBUGP(DLMI, "\n"); if (ret < 0) { @@ -383,7 +140,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, } unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT); unitid[len - 1] = '\0'; - ipaccess_parse_unitid(unitid, &unit_data); + ipa_parse_unitid(unitid, &unit_data); if (!line->ops->sign_link_up) { LOGP(DLINP, LOGL_ERROR, @@ -528,25 +285,6 @@ err: return ret; } -void ipaccess_prepend_header_ext(struct msgb *msg, int proto) -{ - struct ipaccess_head_ext *hh_ext; - - /* prepend the osmo ip.access header extension */ - hh_ext = (struct ipaccess_head_ext *) msgb_push(msg, sizeof(*hh_ext)); - hh_ext->proto = proto; -} - -void ipaccess_prepend_header(struct msgb *msg, int proto) -{ - struct ipaccess_head *hh; - - /* prepend the ip.access header */ - hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh)); - hh->len = htons(msg->len - sizeof(*hh)); - hh->proto = proto; -} - static int ts_want_write(struct e1inp_ts *e1i_ts) { e1i_ts->driver.ipaccess.fd.when |= BSC_FD_WRITE; @@ -598,7 +336,7 @@ static int __handle_ts1_write(struct osmo_fd *bfd, struct e1inp_line *line) } msg->l2h = msg->data; - ipaccess_prepend_header(msg, sign_link->tei); + ipa_prepend_header(msg, sign_link->tei); DEBUGP(DLMI, "TX %u: %s\n", ts_nr, osmo_hexdump(msg->l2h, msgb_l2len(msg))); @@ -752,7 +490,7 @@ static int ipaccess_bsc_oml_cb(struct ipa_server_link *link, int fd) update_fd_settings(line, bfd->fd); /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */ - ret = ipaccess_send_id_req(bfd->fd); + ret = ipa_ccm_send_id_req(bfd->fd); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "could not send ID REQ. Reason: %s\n", strerror(errno)); @@ -805,7 +543,7 @@ static int ipaccess_bsc_rsl_cb(struct ipa_server_link *link, int fd) goto err_line; } /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */ - ret = ipaccess_send_id_req(bfd->fd); + ret = ipa_ccm_send_id_req(bfd->fd); if (ret < 0) { LOGP(DLINP, LOGL_ERROR, "could not send ID REQ. Reason: %s\n", strerror(errno)); @@ -939,7 +677,7 @@ int ipaccess_bts_handle_ccm(struct ipa_client_conn *link, uint8_t msg_type = *(msg->l2h); /* ping, pong and acknowledgment cases. */ - ret = ipaccess_rcvmsg_bts_base(msg, link->ofd); + ret = ipa_ccm_rcvmsg_bts_base(msg, link->ofd); if (ret < 0) goto err; @@ -950,8 +688,7 @@ int ipaccess_bts_handle_ccm(struct ipa_client_conn *link, LOGP(DLINP, LOGL_NOTICE, "received ID get\n"); rmsg = ipa_bts_id_resp(dev, data + 1, len - 1); - ret = ipaccess_send(link->ofd->fd, rmsg->data, - rmsg->len); + ret = ipa_send(link->ofd->fd, rmsg->data, rmsg->len); if (ret != rmsg->len) { LOGP(DLINP, LOGL_ERROR, "cannot send ID_RESP " "message. Reason: %s\n", strerror(errno)); @@ -961,8 +698,7 @@ int ipaccess_bts_handle_ccm(struct ipa_client_conn *link, /* send ID_ACK. */ rmsg = ipa_bts_id_ack(); - ret = ipaccess_send(link->ofd->fd, rmsg->data, - rmsg->len); + ret = ipa_send(link->ofd->fd, rmsg->data, rmsg->len); if (ret != rmsg->len) { LOGP(DLINP, LOGL_ERROR, "cannot send ID_ACK " "message. Reason: %s\n", strerror(errno)); diff --git a/tests/e1inp_ipa_bts_test.c b/tests/e1inp_ipa_bts_test.c index 02a4cb3..18f1709 100644 --- a/tests/e1inp_ipa_bts_test.c +++ b/tests/e1inp_ipa_bts_test.c @@ -9,6 +9,7 @@ #include <osmocom/core/application.h> #include <osmocom/abis/ipaccess.h> #include <osmocom/gsm/protocol/gsm_12_21.h> +#include <osmocom/gsm/ipa.h> static void *tall_test; static struct e1inp_sign_link *oml_sign_link, *rsl_sign_link; |