Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
pespin committed Dec 18, 2023
1 parent a7d5114 commit 5322e15
Show file tree
Hide file tree
Showing 13 changed files with 644 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
200 changes: 200 additions & 0 deletions lib/gtp/v1/types.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,3 +398,203 @@ int16_t ogs_gtp1_build_qos_profile(ogs_tlv_octet_t *octet,
octet->len = 6;
return octet->len;
}

/* 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;
}

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;
uint8_t qos_sub[OGS_GTP1_QOS_PROFILE_MAX_LEN];
uint8_t qos_sub_len;
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);

CHECK_SPACE_ERR(1 + OGS_GTP1_QOS_PROFILE_MAX_LEN);
//*ptr++ = decoded->qos_sub_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;

CHECK_SPACE_ERR(1);
*ptr++ = decoded->qos_req_len;
CHECK_SPACE_ERR(decoded->qos_req_len);
memcpy(ptr, &decoded->qos_req[0], decoded->qos_req_len);
ptr += decoded->qos_req_len;

CHECK_SPACE_ERR(1);
*ptr++ = decoded->qos_neg_len;
CHECK_SPACE_ERR(decoded->qos_neg_len);
memcpy(ptr, &decoded->qos_neg[0], decoded->qos_neg_len);
ptr += decoded->qos_neg_len;

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
}
49 changes: 49 additions & 0 deletions lib/gtp/v1/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,53 @@ int16_t ogs_gtp1_parse_qos_profile(
int16_t ogs_gtp1_build_qos_profile(ogs_tlv_octet_t *octet,
const ogs_gtp1_qos_profile_decoded_t *decoded, void *data, int data_len);

/* Extended End User Address. Not explicitly defined in a table: */
#define OGS_GTP1_PDPCTX_EXT_EUA_NO 0
#define OGS_GTP1_PDPCTX_EXT_EUA_YES 1

/* 7.7.29 Table 48 Reordering Required Values */
#define OGS_GTP1_PDPCTX_REORDERING_REQUIRED_NO 0
#define OGS_GTP1_PDPCTX_REORDERING_REQUIRED_YES 1

/* 7.7.29 Table 49 VPLMN Address Allowed Values */
#define OGS_GTP1_PDPCTX_VLPMN_ADDR_ALLOWED_NO 0
#define OGS_GTP1_PDPCTX_VLPMN_ADDR_ALLOWED_YES 1

/* 7.7.29 Table 49A Activity Status Indicator Value */
#define OGS_GTP1_PDPCTX_ACTIVITY_STATUS_IND_YES 0
#define OGS_GTP1_PDPCTX_ACTIVITY_STATUS_IND_NO 1

typedef struct ogs_gtp1_pdp_context_decoded_s {
uint8_t ea:1; /* OGS_GTP1_PDPCTX_EXT_EUA_* */
uint8_t vaa:1; /* OGS_GTP1_PDPCTX_VLPMN_ADDR_ALLOWED_* */
uint8_t asi:1; /* OGS_GTP1_PDPCTX_ACTIVITY_STATUS_IND_* */
uint8_t order:1; /* OGS_GTP1_PDPCTX_REORDERING_REQUIRED_* */
uint8_t nsapi:4;
uint8_t sapi:4;
ogs_gtp1_qos_profile_decoded_t qos_sub;
//uint8_t qos_sub[OGS_GTP1_QOS_PROFILE_MAX_LEN];
//uint8_t qos_sub_len;
uint8_t qos_req[OGS_GTP1_QOS_PROFILE_MAX_LEN];
uint8_t qos_req_len;
uint8_t qos_neg[OGS_GTP1_QOS_PROFILE_MAX_LEN];
uint8_t qos_neg_len;
uint16_t snd;
uint16_t snu;
uint8_t send_npdu_nr;
uint8_t receive_npdu_nr;
uint32_t ul_teic;
uint32_t ul_teid;
uint8_t pdp_ctx_id;
uint8_t pdp_type_org;
uint8_t pdp_type_num[2];
ogs_ip_t pdp_address[2];
ogs_ip_t ggsn_address_c;
ogs_ip_t ggsn_address_u;
char apn[OGS_MAX_APN_LEN+1];
uint16_t trans_id:12;
} ogs_gtp1_pdp_context_decoded_t;

int ogs_gtp1_build_pdp_context(ogs_gtp1_tlv_pdp_context_t *octet,
const ogs_gtp1_pdp_context_decoded_t *decoded, uint8_t *data, int data_len);

#endif /* OGS_GTP1_TYPES_H */
3 changes: 3 additions & 0 deletions src/mme/mme-context.c
Original file line number Diff line number Diff line change
Expand Up @@ -3161,6 +3161,9 @@ void mme_ue_confirm_guti(mme_ue_t *mme_ue)
memcpy(&mme_ue->current.guti,
&mme_ue->next.guti, sizeof(ogs_nas_eps_guti_t));

ogs_warn("PESPIN: Adding GUTI[G:%d,C:%d,M_TMSI:0x%x]\n",
mme_ue->current.guti.mme_gid, mme_ue->current.guti.mme_code, mme_ue->current.guti.m_tmsi);

/* Hashing Current GUTI */
ogs_hash_set(self.guti_ue_hash,
&mme_ue->current.guti, sizeof(ogs_nas_eps_guti_t), mme_ue);
Expand Down
5 changes: 5 additions & 0 deletions src/mme/mme-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,11 @@ struct mme_ue_s {
char a_msisdn_bcd[OGS_MAX_MSISDN_BCD_LEN+1];

mme_p_tmsi_t p_tmsi;
struct {
uint32_t sgsn_gn_teid;
ogs_ip_t sgsn_gn_ip;
ogs_ip_t sgsn_gn_ip_alt;
} gn;

struct {
mme_m_tmsi_t *m_tmsi;
Expand Down
Loading

0 comments on commit 5322e15

Please sign in to comment.