aboutsummaryrefslogtreecommitdiffstats
path: root/src/iu_helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iu_helpers.c')
-rw-r--r--src/iu_helpers.c164
1 files changed, 163 insertions, 1 deletions
diff --git a/src/iu_helpers.c b/src/iu_helpers.c
index bf82fde..5c7ff31 100644
--- a/src/iu_helpers.c
+++ b/src/iu_helpers.c
@@ -24,8 +24,12 @@
#include <arpa/inet.h>
#include "asn1helpers.h"
#include <osmocom/core/utils.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/bit16gen.h>
+
#include <osmocom/ranap/RANAP_IuTransportAssociation.h>
#include <osmocom/ranap/RANAP_TransportLayerAddress.h>
+#include <osmocom/ranap/RANAP_TransportLayerInformation.h>
/* decode a BCD-string as used inside ASN.1 encoded Iu interface protocols */
int ranap_bcd_decode(char *out, size_t out_len, const uint8_t *in, size_t in_len)
@@ -109,7 +113,7 @@ int ranap_transp_layer_addr_decode(char *addr, unsigned int addr_len,
buf = trasp_layer_addr->buf;
len = trasp_layer_addr->size;
- if (buf[0] == 0x35 && len >= 7)
+ if (len >= 7 && buf[0] == 0x35)
rc = inet_ntop(AF_INET, buf + 3, addr, addr_len);
else if (len > 3)
rc = inet_ntop(AF_INET, buf, addr, addr_len);
@@ -121,3 +125,161 @@ int ranap_transp_layer_addr_decode(char *addr, unsigned int addr_len,
return 0;
}
+
+/* (same as ranap_transp_layer_addr_decode, but AF agnostic) */
+int ranap_transp_layer_addr_decode2(struct osmo_sockaddr *addr, bool *uses_x213_nsap,
+ const RANAP_TransportLayerAddress_t *trasp_layer_addr)
+{
+ unsigned char *buf;
+ int len;
+ bool x213_nsap = false;
+ uint16_t icp;
+
+ buf = trasp_layer_addr->buf;
+ len = trasp_layer_addr->size;
+
+ memset(addr, 0, sizeof(*addr));
+
+ if ((len == 7 || len == 20) && buf[0] == 0x35) {
+ /* ITU-T Rec. X.213 A.5.2.1.2.7, RFC 1888 section 6
+ * For an X.213 NSAP encoded address we expect:
+ * 3 bytes IDP (first byte AFI = 0x35, which means that two byte IDI and an IP address follows)
+ * Either 4 or 17 bytes of DSP containing the IP address.
+ * (see also comments in function ranap_new_transp_layer_addr below) */
+ x213_nsap = true;
+ icp = osmo_load16be(&buf[1]);
+ switch (icp) {
+ case 0x0000:
+ /* "RFC 1888 provides guidance on how to embed an IPv6 address within the DSP of an NSAP
+ * address. The IPv6 address is carried in the first 16 octets of the DSP.
+ * Octet 17 of the DSP is set to zero, but has no significance for IPv6." */
+ if (len != 20)
+ return -EINVAL;
+ addr->u.sa.sa_family = AF_INET6;
+ memcpy(addr->u.sin6.sin6_addr.s6_addr, buf + 3, sizeof(addr->u.sin6.sin6_addr.s6_addr));
+ break;
+ case 0x0001:
+ addr->u.sa.sa_family = AF_INET;
+ memcpy((uint8_t *) &addr->u.sin.sin_addr.s_addr, buf + 3, sizeof(addr->u.sin.sin_addr.s_addr));
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else if (len == 4) {
+ /* A non X.213 NSAP encoded IPv4 address is 4 bytes long */
+ addr->u.sa.sa_family = AF_INET;
+ memcpy((uint8_t *) &addr->u.sin.sin_addr.s_addr, buf, sizeof(addr->u.sin.sin_addr.s_addr));
+ } else if (len == 16) {
+ /* A non X.213 NSAP encoded IPv6 address is 16 bytes long */
+ addr->u.sa.sa_family = AF_INET6;
+ memcpy(addr->u.sin6.sin6_addr.s6_addr, buf, sizeof(addr->u.sin6.sin6_addr.s6_addr));
+ } else
+ return -EINVAL;
+
+ /* In case the caller is interested in the encoding method that was used */
+ if (uses_x213_nsap)
+ *uses_x213_nsap = x213_nsap;
+
+ return 0;
+}
+
+int ranap_new_transp_layer_addr(BIT_STRING_t *out, struct osmo_sockaddr *addr, bool use_x213_nsap)
+{
+ uint8_t *buf;
+ unsigned int len;
+ size_t ip_len;
+ uint8_t *ip_addr;
+ uint16_t icp;
+
+ switch (addr->u.sa.sa_family) {
+ case AF_INET:
+ ip_len = sizeof(addr->u.sin.sin_addr.s_addr);
+ ip_addr = (uint8_t *) &addr->u.sin.sin_addr.s_addr;
+ icp = 0x0001; /* See X.213, section A.5.2.1.2.7 */
+ break;
+ case AF_INET6:
+ ip_len = sizeof(addr->u.sin6.sin6_addr.s6_addr);
+ ip_addr = addr->u.sin6.sin6_addr.s6_addr;
+ icp = 0x0000; /* See X.213, section A.5.2.1.2.7 */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (use_x213_nsap) {
+ /* 3 bytes IDP (AFI+ICP) + 17 bytes DSP */
+ len = 3 + 17;
+ buf = CALLOC(len, sizeof(uint8_t));
+
+ /* 1 byte AFI to announce IANA ICP, see also X.213, table A.4 */
+ buf[0] = 0x35;
+
+ /* 2 byte IANA ICP IDI, see also X.213, A.5.2.1.2.7 */
+ osmo_store16be(icp, &buf[1]);
+
+ /* 17 byte DSP, see also X.213, table A.5 and A.5.2.1.2.7 */
+ memcpy(&buf[3], ip_addr, ip_len);
+ } else {
+ len = ip_len;
+ buf = CALLOC(len, sizeof(uint8_t));
+ memcpy(buf, ip_addr, ip_len);
+ }
+ if (out->buf)
+ FREEMEM(out->buf);
+ out->buf = buf;
+ out->size = len;
+ out->bits_unused = 0;
+
+ return 0;
+}
+
+RANAP_TransportLayerInformation_t *ranap_new_transp_info_rtp(struct osmo_sockaddr *addr, bool use_x213_nsap)
+{
+ RANAP_TransportLayerInformation_t *tli;
+ uint8_t binding_id[4] = { 0 };
+ int rc;
+
+ switch (addr->u.sin.sin_family) {
+ case AF_INET:
+ osmo_store16be(ntohs(addr->u.sin.sin_port), binding_id);
+ break;
+ case AF_INET6:
+ osmo_store16be(ntohs(addr->u.sin6.sin6_port), binding_id);
+ break;
+ default:
+ return NULL;
+ }
+
+ tli = CALLOC(1, sizeof(*tli));
+ rc = ranap_new_transp_layer_addr(&tli->transportLayerAddress, addr, use_x213_nsap);
+ if (rc < 0) {
+ ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli);
+ return NULL;
+ }
+
+ tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_bindingID;
+ OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.bindingID,
+ (const char *)binding_id, sizeof(binding_id));
+
+ return tli;
+}
+
+RANAP_TransportLayerInformation_t *ranap_new_transp_info_gtp(struct osmo_sockaddr *addr, uint32_t tei,
+ bool use_x213_nsap)
+{
+ RANAP_TransportLayerInformation_t *tli = CALLOC(1, sizeof(*tli));
+ uint32_t binding_buf = htonl(tei);
+ int rc;
+
+ rc = ranap_new_transp_layer_addr(&tli->transportLayerAddress, addr, use_x213_nsap);
+ if (rc < 0) {
+ ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli);
+ return NULL;
+ }
+
+ tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_gTP_TEI;
+ OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.gTP_TEI,
+ (const char *)&binding_buf, sizeof(binding_buf));
+
+ return tli;
+}