Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
pespin committed Dec 19, 2023
1 parent 5061a3a commit 948c2f7
Show file tree
Hide file tree
Showing 13 changed files with 836 additions and 1 deletion.
28 changes: 28 additions & 0 deletions lib/gtp/v1/conv.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,34 @@ int ogs_gtp1_gsn_addr_to_ip(const ogs_gtp1_gsn_addr_t *gsnaddr, uint16_t gsnaddr
return OGS_OK;
}

int ogs_gtp1_pdu_session_type_to_eua_ietf_type(uint8_t session_type)
{
switch (session_type) {
case OGS_PDU_SESSION_TYPE_IPV4:
return OGS_PDP_EUA_IETF_IPV4;
case OGS_PDU_SESSION_TYPE_IPV6:
return OGS_PDP_EUA_IETF_IPV6;
case OGS_PDU_SESSION_TYPE_IPV4V6:
return OGS_PDP_EUA_IETF_IPV4V6;
default:
return OGS_ERROR;
}
}

int ogs_gtp1_eua_ietf_type_to_pdu_session_type(uint8_t eua_ietf_type)
{
switch (eua_ietf_type) {
case OGS_PDP_EUA_IETF_IPV4:
return OGS_PDU_SESSION_TYPE_IPV4;
case OGS_PDP_EUA_IETF_IPV6:
return OGS_PDU_SESSION_TYPE_IPV6;
case OGS_PDP_EUA_IETF_IPV4V6:
return OGS_PDU_SESSION_TYPE_IPV4V6;
default:
return OGS_ERROR;
}
}

int ogs_gtp1_eua_to_ip(const ogs_eua_t *eua, uint16_t eua_len, ogs_ip_t *ip,
uint8_t *pdu_session_type)
{
Expand Down
3 changes: 3 additions & 0 deletions lib/gtp/v1/conv.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ int ogs_gtp1_sockaddr_to_gsn_addr(const ogs_sockaddr_t *addr,
int ogs_gtp1_gsn_addr_to_ip(const ogs_gtp1_gsn_addr_t *gsnaddr, uint16_t gsnaddr_len,
ogs_ip_t *ip);

int ogs_gtp1_pdu_session_type_to_eua_ietf_type(uint8_t session_type);
int ogs_gtp1_eua_ietf_type_to_pdu_session_type(uint8_t eua_ietf_type);

int ogs_gtp1_eua_to_ip(const ogs_eua_t *eua, uint16_t eua_len, ogs_ip_t *ip,
uint8_t *pdu_session_type);

Expand Down
308 changes: 308 additions & 0 deletions lib/gtp/v1/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,3 +398,311 @@ int16_t ogs_gtp1_build_qos_profile(ogs_tlv_octet_t *octet,
octet->len = 6;
return octet->len;
}

/* 7.7.28 MM Context */
/* TODO: UMTS support, see Figure 41 and Figure 42. */
int ogs_gtp1_build_mm_context(ogs_gtp1_tlv_mm_context_t *octet,
const ogs_gtp1_mm_context_decoded_t *decoded, uint8_t *data, int data_len)
{
uint8_t *ptr = data;
unsigned int i;
uint16_t *len_ptr;

ogs_assert(octet);
ogs_assert(data);
ogs_assert((size_t)data_len >= 1);

octet->data = data;

#define CHECK_SPACE_ERR(bytes) \
if ((ptr - data) + (bytes) > data_len) \
return OGS_ERROR
CHECK_SPACE_ERR(1);
*ptr++ = (decoded->gupii & 0x01) << 7 |
(decoded->ugipai & 0x01) << 6 |
(decoded->used_gprs_protection_algo & 0x07) << 3 |
(decoded->ksi & 0x07);

CHECK_SPACE_ERR(1);
*ptr++ = (decoded->sec_mode & 0x03) << 6 |
(decoded->num_vectors & 0x07) << 3 |
0x07;

CHECK_SPACE_ERR(sizeof(decoded->ck));
memcpy(ptr, &decoded->ck[0], sizeof(decoded->ck));
ptr += sizeof(decoded->ck);

CHECK_SPACE_ERR(sizeof(decoded->ik));
memcpy(ptr, &decoded->ik[0], sizeof(decoded->ik));
ptr += sizeof(decoded->ik);

/* Quintuplet Length */
CHECK_SPACE_ERR(1);
len_ptr = (uint16_t *)ptr; /* will be filled later */
ptr += 2;

for (i = 0; i < decoded->num_vectors; i++) {
CHECK_SPACE_ERR(sizeof(decoded->auth_quintuplets[0]));

memcpy(ptr, &decoded->auth_quintuplets[i].rand, sizeof(decoded->auth_quintuplets[i].rand));
ptr += sizeof(decoded->auth_quintuplets[i].rand);

*ptr++ = decoded->auth_quintuplets[i].xres_len;
memcpy(ptr, &decoded->auth_quintuplets[i].xres[0], decoded->auth_quintuplets[i].xres_len);
ptr += decoded->auth_quintuplets[i].xres_len;

memcpy(ptr, &decoded->auth_quintuplets[i].ck, sizeof(decoded->auth_quintuplets[i].ck));
ptr += sizeof(decoded->auth_quintuplets[i].ck);
memcpy(ptr, &decoded->auth_quintuplets[i].ik, sizeof(decoded->auth_quintuplets[i].ik));
ptr += sizeof(decoded->auth_quintuplets[i].ik);

*ptr++ = decoded->auth_quintuplets[i].autn_len;
memcpy(ptr, &decoded->auth_quintuplets[i].autn[0], decoded->auth_quintuplets[i].autn_len);
ptr += decoded->auth_quintuplets[i].autn_len;
}

*len_ptr = htobe16(ptr - (((uint8_t *)len_ptr) + 2));

CHECK_SPACE_ERR(sizeof(decoded->drx_param));
memcpy(ptr, &decoded->drx_param, sizeof(decoded->drx_param));
ptr += sizeof(decoded->drx_param);

CHECK_SPACE_ERR(decoded->ms_network_capability_len);
memcpy(ptr, &decoded->ms_network_capability, decoded->ms_network_capability_len);
ptr += decoded->ms_network_capability_len;

if (decoded->imeisv_len != 0) {
/* Container Len */
CHECK_SPACE_ERR(1);
*ptr++ = decoded->imeisv_len != 0;
/* Container (Mobile Identity IMEISV), TS 29.060 Table 47A */
CHECK_SPACE_ERR(1);
*ptr++ = 0x23;

CHECK_SPACE_ERR(1);
*ptr++ = 0x23; /* Length of mobile identity contents */

CHECK_SPACE_ERR(decoded->imeisv_len);
memcpy(ptr, &decoded->imeisv[0], decoded->imeisv_len);
ptr += decoded->imeisv_len;
} else {
/* Container Len */
CHECK_SPACE_ERR(1);
*ptr++ = 0;
}

if (decoded->nrsrna) {
CHECK_SPACE_ERR(2);
*ptr++ = 1;
*ptr++ = 0x01;
}

octet->len = (ptr - data);
return OGS_OK;
#undef CHECK_SPACE_ERR
}

/* The format of EUA in PDP Context is not exactly the same for the entire EUA,
* hence a separate function is required to encode the value part of the address,
* instead of using regular ogs_gtp1_ip_to_eua(). */
static int enc_pdp_ctx_as_eua(uint8_t pdu_session_type, const ogs_ip_t *ip,
uint8_t *data, int data_len)
{
ogs_debug("PESPIN: enc_pdp_ctx_as_eua(sess_type=%u, data_len=%u)\n", pdu_session_type, data_len);

switch (pdu_session_type)
{
case OGS_PDU_SESSION_TYPE_IPV4:
if (!ip->ipv4) {
ogs_error("EUA type IPv4 but no IPv4 address available");
return OGS_ERROR;
}
if (data_len < OGS_IPV4_LEN)
return OGS_ERROR;
memcpy(data, &ip->addr, OGS_IPV4_LEN);
return OGS_IPV4_LEN;
case OGS_PDU_SESSION_TYPE_IPV6:
if (!ip->ipv6) {
ogs_error("EUA type IPv4 but no IPv6 address available");
return OGS_ERROR;
}
if (data_len < OGS_IPV6_LEN)
return OGS_ERROR;
memcpy(data, ip->addr6, OGS_IPV6_LEN);
return OGS_IPV6_LEN;
case OGS_PDU_SESSION_TYPE_IPV4V6:
if (ip->ipv4 && ip->ipv6) {
if (data_len < OGS_IPV4_LEN + OGS_IPV6_LEN)
return OGS_ERROR;
memcpy(data, &ip->addr, OGS_IPV4_LEN);
memcpy(data + OGS_IPV4_LEN, ip->addr6, OGS_IPV6_LEN);
return OGS_IPV4_LEN + OGS_IPV6_LEN;
} else if (ip->ipv4) {
if (data_len < OGS_IPV4_LEN)
return OGS_ERROR;
memcpy(data, &ip->addr, OGS_IPV4_LEN);
return OGS_IPV4_LEN;
} else if (ip->ipv6) {
if (data_len < OGS_IPV6_LEN)
return OGS_ERROR;
memcpy(data, ip->addr6, OGS_IPV6_LEN);
return OGS_IPV6_LEN;
} else {
ogs_error("EUA type IPv4 but no IPv4 nor IPv6 address available");
return OGS_ERROR;
}
break;
default:
ogs_error("Unexpected session type");
return OGS_ERROR;
}
return OGS_OK;
}

/* TS 29.060 7.7.29 PDP Context */
int ogs_gtp1_build_pdp_context(ogs_tlv_octet_t *octet,
const ogs_gtp1_pdp_context_decoded_t *decoded, uint8_t *data, int data_len)
{
uint8_t *ptr = data;
uint16_t val16;
uint32_t val32;
int rv;
ogs_tlv_octet_t qos_sub_tlv_unused;

ogs_assert(octet);
ogs_assert(data);
ogs_assert((size_t)data_len >= 1);

octet->data = data;

#define CHECK_SPACE_ERR(bytes) \
if ((ptr - data) + (bytes) > data_len) \
return OGS_ERROR

CHECK_SPACE_ERR(1);
*ptr++ = (decoded->ea << 7) | (decoded->vaa << 6) |
(decoded->asi << 5)| (decoded->order << 4) |
(decoded->nsapi & 0x0f);

CHECK_SPACE_ERR(1);
*ptr++ = (decoded->sapi & 0x0f);

/* Quality of Service Subscribed */
CHECK_SPACE_ERR(1 + OGS_GTP1_QOS_PROFILE_MAX_LEN);
rv = ogs_gtp1_build_qos_profile(&qos_sub_tlv_unused, &decoded->qos_sub,
ptr, (data + data_len) - (ptr + 1));
if (rv < 0)
return rv;
*ptr = rv;
ptr += 1 + rv;

/* Quality of Service Requested */
CHECK_SPACE_ERR(1 + OGS_GTP1_QOS_PROFILE_MAX_LEN);
rv = ogs_gtp1_build_qos_profile(&qos_sub_tlv_unused, &decoded->qos_req,
ptr, (data + data_len) - (ptr + 1));
if (rv < 0)
return rv;
*ptr = rv;
ptr += 1 + rv;

/* Quality of Service Negotiated */
CHECK_SPACE_ERR(1 + OGS_GTP1_QOS_PROFILE_MAX_LEN);
rv = ogs_gtp1_build_qos_profile(&qos_sub_tlv_unused, &decoded->qos_neg,
ptr, (data + data_len) - (ptr + 1));
if (rv < 0)
return rv;
*ptr = rv;
ptr += 1 + rv;

CHECK_SPACE_ERR(2);
val16 = htobe16(decoded->snd);
memcpy(ptr, &val16, 2);
ptr += 2;

CHECK_SPACE_ERR(2);
val16 = htobe16(decoded->snu);
memcpy(ptr, &val16, 2);
ptr += 2;

CHECK_SPACE_ERR(1);
*ptr++ = decoded->send_npdu_nr;

CHECK_SPACE_ERR(1);
*ptr++ = decoded->receive_npdu_nr;

CHECK_SPACE_ERR(4);
val32 = htobe32(decoded->ul_teic);
memcpy(ptr, &val32, 4);
ptr += 4;

CHECK_SPACE_ERR(4);
val32 = htobe32(decoded->ul_teid);
memcpy(ptr, &val32, 4);
ptr += 4;

CHECK_SPACE_ERR(1);
*ptr++ = decoded->pdp_ctx_id;

CHECK_SPACE_ERR(1);
*ptr++ = 0xf0 | decoded->pdp_type_org;
CHECK_SPACE_ERR(1);
*ptr++ = ogs_gtp1_pdu_session_type_to_eua_ietf_type(decoded->pdp_type_num[0]);
/* PDP Address Length filled after PDP Address */
CHECK_SPACE_ERR(1);
rv = enc_pdp_ctx_as_eua(decoded->pdp_type_num[0], &decoded->pdp_address[0],
ptr + 1, (data + data_len) - (ptr + 1));
if (rv < 0)
return rv;
*ptr = rv;
ptr += 1 + rv;

/* GGSN Address for control plane Length */
CHECK_SPACE_ERR(1);
*ptr = decoded->ggsn_address_c.ipv6 ? OGS_GTP_GSN_ADDRESS_IPV6_LEN : OGS_GTP_GSN_ADDRESS_IPV4_LEN;
CHECK_SPACE_ERR(1 + (*ptr));
memcpy(ptr + 1,
decoded->ggsn_address_c.ipv6 ?
(uint8_t *)decoded->ggsn_address_c.addr6 :
(uint8_t *)&decoded->ggsn_address_c.addr,
*ptr);
ptr += 1 + *ptr;

/* GGSN Address for User Traffic Length */
CHECK_SPACE_ERR(1);
*ptr = decoded->ggsn_address_u.ipv6 ? OGS_GTP_GSN_ADDRESS_IPV6_LEN : OGS_GTP_GSN_ADDRESS_IPV4_LEN;
CHECK_SPACE_ERR(1 + (*ptr));
memcpy(ptr + 1,
decoded->ggsn_address_u.ipv6 ?
(uint8_t *)decoded->ggsn_address_u.addr6 :
(uint8_t *)&decoded->ggsn_address_u.addr,
*ptr);
ptr += 1 + *ptr;

/* APN */
rv = strlen(decoded->apn);
CHECK_SPACE_ERR(1 + rv + 1);
*ptr = ogs_fqdn_build(
(char *)ptr + 1, decoded->apn, rv);
ptr += 1 + *ptr;

CHECK_SPACE_ERR(2);
*ptr++ = (decoded->trans_id >> 8) & 0x0f;
*ptr++ = decoded->trans_id & 0xff;

if (decoded->ea == OGS_GTP1_PDPCTX_EXT_EUA_YES) {
CHECK_SPACE_ERR(1);
*ptr++ = decoded->pdp_type_num[1];
/* PDP Address Length filled after PDP Address */
CHECK_SPACE_ERR(1);
rv = enc_pdp_ctx_as_eua(decoded->pdp_type_num[1], &decoded->pdp_address[1],
ptr + 1, (data + data_len) - (ptr + 1));
if (rv < 0)
return rv;
*ptr = rv;
ptr += 1 + rv;
}

octet->len = (ptr - data);
return OGS_OK;
#undef CHECK_SPACE_ERR
}
Loading

0 comments on commit 948c2f7

Please sign in to comment.