aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-04-03 19:25:45 +0200
committerHarald Welte <laforge@gnumonks.org>2017-04-03 22:11:41 +0200
commit1c694b7eaf478a885bfbce75562647cceafc3ee5 (patch)
tree9026840eb72b777999826b8463375dd5b13bbb23
parent178abb9e364d01df222d0b017ef873d9b1ace847 (diff)
sua: Extend address parsing with GT, RI and IPv4 support
-rw-r--r--src/sua.c223
1 files changed, 99 insertions, 124 deletions
diff --git a/src/sua.c b/src/sua.c
index 36032ff..e81bce7 100644
--- a/src/sua.c
+++ b/src/sua.c
@@ -690,117 +690,54 @@ int osmo_sua_user_link_down(struct osmo_sccp_link *link, struct osmo_prim_hdr *o
/***********************************************************************
- * Mandatory IE checking
+ * Receiving SUA messsages from SCTP
***********************************************************************/
-#define MAND_IES(msgt, ies) [msgt] = (ies)
-
-static const uint16_t cldt_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_PROTO_CLASS, SUA_IEI_SRC_ADDR,
- SUA_IEI_DEST_ADDR, SUA_IEI_SEQ_CTRL, SUA_IEI_DATA, 0
-};
-
-static const uint16_t cldr_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_CAUSE, SUA_IEI_SRC_ADDR,
- SUA_IEI_DEST_ADDR, 0
-};
-
-static const uint16_t codt_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, SUA_IEI_DATA, 0
-};
-
-static const uint16_t coda_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, 0
-};
-
-static const uint16_t core_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_PROTO_CLASS, SUA_IEI_SRC_REF,
- SUA_IEI_DEST_ADDR, SUA_IEI_SEQ_CTRL, 0
-};
-
-static const uint16_t coak_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_PROTO_CLASS, SUA_IEI_DEST_REF,
- SUA_IEI_SRC_REF, SUA_IEI_SEQ_CTRL, 0
-};
-
-static const uint16_t coref_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, SUA_IEI_CAUSE, 0
-};
-
-static const uint16_t relre_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, SUA_IEI_SRC_REF,
- SUA_IEI_CAUSE, 0
-};
-
-static const uint16_t relco_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, SUA_IEI_SRC_REF, 0
-};
-
-static const uint16_t resre_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, SUA_IEI_SRC_REF,
- SUA_IEI_CAUSE, 0
-};
-
-static const uint16_t resco_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, SUA_IEI_SRC_REF, 0
-};
-
-static const uint16_t coerr_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_DEST_REF, SUA_IEI_CAUSE, 0
-};
-
-static const uint16_t coit_mand_ies[] = {
- SUA_IEI_ROUTE_CTX, SUA_IEI_PROTO_CLASS, SUA_IEI_SRC_REF,
- SUA_IEI_DEST_REF, 0
-};
-
-static const uint16_t *mand_ies_cl[256] = {
- MAND_IES(SUA_CL_CLDT, cldt_mand_ies),
- MAND_IES(SUA_CL_CLDR, cldr_mand_ies),
-};
+/*! \brief Decode SUA Global Title according to RFC3868 3.10.2.3
+ * \param[out] gt User-allocated structure for decoded output
+ * \param[in] data binary-encoded data
+ * \param[in] datalen length of \ref data in octets
+ */
+int sua_parse_gt(struct osmo_sccp_gt *gt, const uint8_t *data, unsigned int datalen)
+{
+ uint8_t num_digits;
+ char *out_digits;
+ unsigned int i;
-static const uint16_t *mand_ies_co[256] = {
- MAND_IES(SUA_CO_CODT, codt_mand_ies),
- MAND_IES(SUA_CO_CODA, coda_mand_ies),
- MAND_IES(SUA_CO_CORE, core_mand_ies),
- MAND_IES(SUA_CO_COAK, coak_mand_ies),
- MAND_IES(SUA_CO_COREF, coref_mand_ies),
- MAND_IES(SUA_CO_RELRE, relre_mand_ies),
- MAND_IES(SUA_CO_RELCO, relco_mand_ies),
- MAND_IES(SUA_CO_RESRE, resre_mand_ies),
- MAND_IES(SUA_CO_RESCO, resco_mand_ies),
- MAND_IES(SUA_CO_COERR, coerr_mand_ies),
- MAND_IES(SUA_CO_COIT, coit_mand_ies),
-};
+ /* 8 byte header at minimum, plus digits */
+ if (datalen < 8)
+ return -EINVAL;
-static int check_all_mand_ies(const uint16_t **mand_ies, struct xua_msg *xua)
-{
- uint8_t msg_type = xua->hdr.msg_type;
- const uint16_t *ies = mand_ies[msg_type];
- uint16_t ie;
-
- for (ie = *ies; ie; ie = *ies++) {
- if (!xua_msg_find_tag(xua, ie)) {
- LOGP(DSUA, LOGL_ERROR, "SUA Message %u:%u should "
- "contain IE 0x%04x, but doesn't\n",
- xua->hdr.msg_class, msg_type, ie);
- return 0;
- }
+ /* parse header */
+ gt->gti = data[3];
+ num_digits = data[4];
+ gt->tt = data[5];
+ gt->npi = data[6];
+ gt->nai = data[7];
+
+ /* parse digits */
+ out_digits = gt->digits;
+ for (i = 0; i < datalen-8; i++) {
+ uint8_t byte = data[8+i];
+ *out_digits++ = osmo_bcd2char(byte & 0x0F);
+ if (out_digits - gt->digits >= num_digits)
+ break;
+ *out_digits++ = osmo_bcd2char(byte >> 4);
+ if (out_digits - gt->digits >= num_digits)
+ break;
}
+ *out_digits++ = '\0';
- return 1;
+ return 0;
}
-
-/***********************************************************************
- * Receiving SUA messsages from SCTP
- ***********************************************************************/
-
-static int sua_parse_addr(struct osmo_sccp_addr *out,
- struct xua_msg *xua,
- uint16_t iei)
+/*! \brief parse SCCP address from given xUA message part
+ * \param[out] out caller-allocated decoded SCCP address struct
+ * \param[in] param xUA message part containing address
+ \returns 0 on success; negative on error */
+int sua_addr_parse_part(struct osmo_sccp_addr *out,
+ const struct xua_msg_part *param)
{
- const struct xua_msg_part *param = xua_msg_find_tag(xua, iei);
const struct xua_parameter_hdr *par;
uint16_t ri;
uint16_t ai;
@@ -808,16 +745,15 @@ static int sua_parse_addr(struct osmo_sccp_addr *out,
uint16_t par_tag, par_len, par_datalen;
uint32_t *p32;
- if (!param)
- return -ENODEV;
+ memset(out, 0, sizeof(*out));
- LOGP(DSUA, LOGL_DEBUG, "sua_parse_addr(IEI=%d) (%d) %s\n",
- iei, param->len,
+ LOGP(DSUA, LOGL_DEBUG, "%s(IEI=0x%04x) (%d) %s\n", __func__,
+ param->tag, param->len,
osmo_hexdump(param->dat, param->len));
if (param->len < 4) {
- LOGP(DSUA, LOGL_ERROR, "SUA IEI %d: invalid address length: %d\n",
- iei, param->len);
+ LOGP(DSUA, LOGL_ERROR, "SUA IEI 0x%04x: invalid address length: %d\n",
+ param->tag, param->len);
return -EINVAL;
}
@@ -827,16 +763,29 @@ static int sua_parse_addr(struct osmo_sccp_addr *out,
ai = ntohs(*(uint16_t*) &param->dat[pos]);
pos += 2;
- if (ri != SUA_RI_SSN_PC) {
- LOGP(DSUA, LOGL_ERROR, "SUA IEI %d: Routing Indicator not supported yet: %d\n",
- iei, ri);
+ switch (ri) {
+ case SUA_RI_GT:
+ out->ri = OSMO_SCCP_RI_GT;
+ break;
+ case SUA_RI_SSN_PC:
+ out->ri = OSMO_SCCP_RI_SSN_PC;
+ break;
+ case SUA_RI_SSN_IP:
+ out->ri = OSMO_SCCP_RI_SSN_IP;
+ break;
+ case SUA_RI_HOST:
+ default:
+ LOGP(DSUA, LOGL_ERROR, "SUA IEI 0x%04x: Routing Indicator not supported yet: %d\n",
+ param->tag, ri);
return -ENOTSUP;
}
if (ai != 7) {
- LOGP(DSUA, LOGL_ERROR, "SUA IEI %d: Address Indicator not supported yet: %x\n",
- iei, ai);
+#if 0
+ LOGP(DSUA, LOGL_ERROR, "SUA IEI 0x%04x: Address Indicator not supported yet: %x\n",
+ param->tag, ai);
return -ENOTSUP;
+#endif
}
/*
@@ -853,8 +802,8 @@ static int sua_parse_addr(struct osmo_sccp_addr *out,
par_len = ntohs(par->len);
par_datalen = par_len - sizeof(*par);
- LOGP(DSUA, LOGL_DEBUG, "SUA IEI %hu pos %hu/%hu: subpart tag %hu, len %hu\n",
- iei, pos, param->len, par->tag, par->len);
+ LOGP(DSUA, LOGL_DEBUG, "SUA IEI 0x%04x pos %hu/%hu: subpart tag 0x%04x, len %hu\n",
+ param->tag, pos, param->len, par_tag, par_len);
switch (par_tag) {
case SUA_IEI_PC:
@@ -872,12 +821,22 @@ static int sua_parse_addr(struct osmo_sccp_addr *out,
out->presence |= OSMO_SCCP_ADDR_T_SSN;
break;
case SUA_IEI_GT:
- /* TODO */
+ if (par_datalen < 8)
+ goto subpar_fail;
+ sua_parse_gt(&out->gt, par->data, par_datalen);
out->presence |= OSMO_SCCP_ADDR_T_GT;
break;
+ case SUA_IEI_IPv4:
+ if (par_datalen != 4)
+ goto subpar_fail;
+ p32 = (uint32_t*)par->data;
+ /* no endian conversion, both network order */
+ out->ip.v4.s_addr = *p32;
+ out->presence |= OSMO_SCCP_ADDR_T_IPv4;
+ break;
default:
- LOGP(DSUA, LOGL_ERROR, "SUA IEI %d: Unknown subpart tag %hd\n",
- iei, par_tag);
+ LOGP(DSUA, LOGL_ERROR, "SUA IEI 0x%04x: Unknown subpart tag %hd\n",
+ param->tag, par_tag);
goto subpar_fail;
}
@@ -887,11 +846,27 @@ static int sua_parse_addr(struct osmo_sccp_addr *out,
return 0;
subpar_fail:
- LOGP(DSUA, LOGL_ERROR, "Failed to parse subparts of address IEI=%d\n",
- iei);
+ LOGP(DSUA, LOGL_ERROR, "Failed to parse subparts of address IEI=0x%04x\n",
+ param->tag);
return -EINVAL;
}
+/*! \brief parse SCCP address from given xUA message IE
+ * \param[out] out caller-allocated decoded SCCP address struct
+ * \param[in] xua xUA message
+ * \param[in] iei Information Element Identifier inside \ref xua
+ \returns 0 on success; negative on error */
+int sua_addr_parse(struct osmo_sccp_addr *out, struct xua_msg *xua, uint16_t iei)
+{
+ const struct xua_msg_part *param = xua_msg_find_tag(xua, iei);
+ if (!param) {
+ memset(out, 0, sizeof(*out));
+ return -ENODEV;
+ }
+
+ return sua_addr_parse_part(out, param);
+}
+
static int sua_rx_cldt(struct osmo_sccp_link *link, struct xua_msg *xua)
{
struct osmo_scu_prim *prim;
@@ -906,8 +881,8 @@ static int sua_rx_cldt(struct osmo_sccp_link *link, struct xua_msg *xua)
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_UNITDATA,
PRIM_OP_INDICATION, upmsg);
- sua_parse_addr(&param->called_addr, xua, SUA_IEI_DEST_ADDR);
- sua_parse_addr(&param->calling_addr, xua, SUA_IEI_SRC_ADDR);
+ sua_addr_parse(&param->called_addr, xua, SUA_IEI_DEST_ADDR);
+ sua_addr_parse(&param->calling_addr, xua, SUA_IEI_SRC_ADDR);
param->in_sequence_control = xua_msg_get_u32(xua, SUA_IEI_SEQ_CTRL);
protocol_class = xua_msg_get_u32(xua, SUA_IEI_PROTO_CLASS);
param->return_option = protocol_class & 0x80;
@@ -953,8 +928,8 @@ static int sua_rx_core(struct osmo_sccp_link *link, struct xua_msg *xua)
/* fill conn */
conn = conn_create(link);
- sua_parse_addr(&conn->called_addr, xua, SUA_IEI_DEST_ADDR);
- sua_parse_addr(&conn->calling_addr, xua, SUA_IEI_SRC_ADDR);
+ sua_addr_parse(&conn->called_addr, xua, SUA_IEI_DEST_ADDR);
+ sua_addr_parse(&conn->calling_addr, xua, SUA_IEI_SRC_ADDR);
conn->remote_ref = xua_msg_get_u32(xua, SUA_IEI_SRC_REF);
/* fill primitive */