Review at  https://gerrit.osmocom.org/2211

sua: Extend address parsing with GT, RI and IPv4 support

Change-Id: I186df77cbdbedfe1a60b855be3626b6766f4681c
---
M src/sua.c
1 file changed, 104 insertions(+), 129 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmo-sccp refs/changes/11/2211/1

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 @@
 
 
 /***********************************************************************
- * Mandatory IE checking
- ***********************************************************************/
-
-#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),
-};
-
-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),
-};
-
-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;
-               }
-       }
-
-       return 1;
-}
-
-
-/***********************************************************************
  * Receiving SUA messsages from SCTP
  ***********************************************************************/
 
-static int sua_parse_addr(struct osmo_sccp_addr *out,
-                         struct xua_msg *xua,
-                         uint16_t iei)
+/*! \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)
 {
-       const struct xua_msg_part *param = xua_msg_find_tag(xua, iei);
+       uint8_t num_digits;
+       char *out_digits;
+       unsigned int i;
+
+       /* 8 byte header at minimum, plus digits */
+       if (datalen < 8)
+               return -EINVAL;
+
+       /* 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 0;
+}
+
+/*! \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_parameter_hdr *par;
        uint16_t ri;
        uint16_t ai;
@@ -808,16 +745,15 @@
        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 @@
        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 @@
                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 @@
                        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,9 +846,25 @@
        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)
@@ -906,8 +881,8 @@
        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 @@
 
        /* 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 */

-- 
To view, visit https://gerrit.osmocom.org/2211
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I186df77cbdbedfe1a60b855be3626b6766f4681c
Gerrit-PatchSet: 1
Gerrit-Project: libosmo-sccp
Gerrit-Branch: master
Gerrit-Owner: Harald Welte <[email protected]>

Reply via email to