open5gs/lib/gtp/v1/conv.c

303 lines
8.7 KiB
C
Raw Normal View History

Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
/*
* Copyright (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ogs-gtp.h"
int ogs_gtp1_gsn_addr_to_sockaddr(const ogs_gtp1_gsn_addr_t *gsnaddr,
uint16_t gsnaddr_len, uint16_t port, ogs_sockaddr_t **list)
{
ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
ogs_assert(gsnaddr);
ogs_assert(list);
switch (gsnaddr_len) {
case OGS_GTP_GSN_ADDRESS_IPV4_LEN:
addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
if (!addr) {
ogs_error("ogs_calloc() failed");
return OGS_ERROR;
}
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
addr->ogs_sa_family = AF_INET;
addr->ogs_sin_port = port;
addr->sin.sin_addr.s_addr = gsnaddr->addr;
*list = addr;
break;
case OGS_GTP_GSN_ADDRESS_IPV6_LEN:
addr6 = ogs_calloc(1, sizeof(ogs_sockaddr_t));
if (!addr6) {
ogs_error("ogs_calloc() failed");
return OGS_ERROR;
}
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
addr6->ogs_sa_family = AF_INET6;
addr6->ogs_sin_port = port;
memcpy(addr6->sin6.sin6_addr.s6_addr, gsnaddr->addr6, OGS_IPV6_LEN);
*list = addr6;
break;
default:
ogs_error("No IPv4 or IPv6");
return OGS_ERROR;
}
return OGS_OK;
}
int ogs_gtp1_sockaddr_to_gsn_addr(const ogs_sockaddr_t *addr,
const ogs_sockaddr_t *addr6, ogs_gtp1_gsn_addr_t *gsnaddr, int *len)
{
ogs_assert(gsnaddr);
if (addr && addr6) {
ogs_error("GSN Address: Both IPv4 and IPv6 not supported");
return OGS_ERROR;
} else if (addr) {
gsnaddr->addr = addr->sin.sin_addr.s_addr;
*len = OGS_GTP_GSN_ADDRESS_IPV4_LEN;
} else if (addr6) {
memcpy(gsnaddr->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
*len = OGS_GTP_GSN_ADDRESS_IPV6_LEN;
} else {
ogs_error("No IPv4 or IPv6");
return OGS_ERROR;
}
return OGS_OK;
}
int ogs_gtp1_gsn_addr_to_ip(const ogs_gtp1_gsn_addr_t *gsnaddr, uint16_t gsnaddr_len,
ogs_ip_t *ip)
{
ogs_assert(ip);
ogs_assert(gsnaddr);
memset(ip, 0, sizeof(ogs_ip_t));
if (gsnaddr_len == OGS_GTP_GSN_ADDRESS_IPV4_LEN) {
ip->ipv4 = 1;
ip->ipv6 = 0;
ip->addr = gsnaddr->addr;
} else if (gsnaddr_len == OGS_GTP_GSN_ADDRESS_IPV6_LEN) {
ip->ipv4 = 0;
ip->ipv6 = 1;
memcpy(ip->addr6, gsnaddr->addr6, OGS_IPV6_LEN);
} else {
ogs_error("No IPv4 or IPv6");
return OGS_ERROR;
}
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;
}
}
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
int ogs_gtp1_eua_to_ip(const ogs_eua_t *eua, uint16_t eua_len, ogs_ip_t *ip,
uint8_t *pdu_session_type)
{
ogs_assert(eua);
ogs_assert(ip);
memset(ip, 0, sizeof *ip);
switch (eua->organization) {
case OGS_PDP_EUA_ORG_IETF:
break;
case OGS_PDP_EUA_ORG_ETSI:
default:
ogs_error("Unsupported EUA organization %u", eua->organization);
return OGS_ERROR;
}
eua_len -= 2;
switch (eua->type) {
case OGS_PDP_EUA_IETF_IPV4:
if (eua_len == OGS_IPV4_LEN) {
ip->addr = eua->addr;
} else if (eua_len != 0) {
ogs_error("Wrong IPv4 EUA length %u", eua_len);
return OGS_ERROR;
}
ip->ipv4 = 1;
ip->ipv6 = 0;
*pdu_session_type = OGS_PDU_SESSION_TYPE_IPV4;
break;
case OGS_PDP_EUA_IETF_IPV6:
if (eua_len == OGS_IPV6_LEN) {
memcpy(ip->addr6, eua->addr6, OGS_IPV6_LEN);
} else if (eua_len != 0) {
ogs_error("Wrong IPv6 EUA length %u", eua_len);
return OGS_ERROR;
}
ip->ipv4 = 0;
ip->ipv6 = 1;
*pdu_session_type = OGS_PDU_SESSION_TYPE_IPV6;
break;
case OGS_PDP_EUA_IETF_IPV4V6:
if (eua_len == OGS_IPV4_LEN) {
ip->addr = eua->addr;
} else if (eua_len == OGS_IPV6_LEN) {
memcpy(ip->addr6, eua->addr6, OGS_IPV6_LEN);
} else if (eua_len == OGS_IPV4_LEN + OGS_IPV6_LEN) {
ip->addr = eua->both.addr;
memcpy(ip->addr6, eua->both.addr6, OGS_IPV6_LEN);
} else if (eua_len != 0) {
ogs_error("Wrong IPv4v6 EUA length %u", eua_len);
return OGS_ERROR;
}
ip->ipv4 = 1;
ip->ipv6 = 1;
*pdu_session_type = OGS_PDU_SESSION_TYPE_IPV4V6;
break;
default:
ogs_error("No IPv4 or IPv6");
return OGS_ERROR;
}
return OGS_OK;
}
int ogs_gtp1_ip_to_eua(uint8_t pdu_session_type, const ogs_ip_t *ip,
ogs_eua_t *eua, uint8_t *eua_len)
{
ogs_assert(eua);
ogs_assert(ip);
ogs_assert(eua_len);
memset(eua, 0, sizeof *eua);
eua->spare = 0xf; /* TS 29.060 Figure 35 */
Introduce Gn interface (GTPv1C) Support to PGW (#1351) * [CORE] tlv: Store mode in ogs_tlv_t This allows specifying the format of the IE for each individual IE, hence allowing messages containing IEs formatted in different ways. This is needed in order to support parsing GTPv1-C, since messages contain IEs with different structure (TLV vs TV). Hence, this is a preparation patch to add support for parsing TVs in ogs-tlv.c/.h. * [CORE] tlv: Support parsing msg with both TLV and TV in it IEs of type TV are sometimes used in GTPv1-C. Current tlv parser/builder doesn't provide with ways to parse messages which contain TV formatted IEs. This patch adds the relevant types and ways to encode/decode them. Furthermore, the current parser/builder allows parsing/building messages containing the exact same format in all its IEs. A new parser function is added which allows parsing messages of different types (TV, TLV) mixed in the same message. In order to be able to do so, it uses the general msg_mode passed to it in order to know the general TLV format (in essence, the length of the Tag field, and also the length of the Length field if applicable each IE). Looking up the instance in the TLV description is left undone and hadcoded to 0, since the only user so far requiring this API is GTPv1-C, which has no instances. * [CORE] tlv: Support repeated tag+instance parsing TLV message In GTPv2C, repeated IEs (same tag) are easily differentiated by the Instance byte, which provides info to match different decoded structures. In GTPv1C though, there's no Instance byte, and we still encounter repeated IEs (like GSN Address in Create PDP Context Request). Hence, the TLV decoder needs to be updated to track count of IEs found (identified by tag+instance, where instance is always 0 in GTPv1C) and get the proper description index + offset into the decoded structure. * [GTP]: Move GTPv2-C specifics to its own libgtp subdir This will allow adding GTPv1-C code by the side. Most GTPv2 code is left in this patch as "gtp" instead of renaming it to "gtp2" in order to avoid massive changes. It can be done at a later stage if wanted. * [GTP] Support generating GTPv1-C messages * [SMF] Add Gn interface support This patch introduces GTPv1C support to open5gs-smfd. With it, open5gs-becomes a GGSN too, where SGSN can connect to, hence supporting GERAN and UTRAN networks.
2022-02-18 13:23:45 +00:00
eua->organization = OGS_PDP_EUA_ORG_IETF;
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;
}
eua->addr = ip->addr;
*eua_len = 2 + OGS_IPV4_LEN;
eua->type = OGS_PDP_EUA_IETF_IPV4;
break;
case OGS_PDU_SESSION_TYPE_IPV6:
if (!ip->ipv6) {
ogs_error("EUA type IPv4 but no IPv6 address available");
return OGS_ERROR;
}
memcpy(eua->addr6, ip->addr6, OGS_IPV6_LEN);
*eua_len = 2 + OGS_IPV6_LEN;
eua->type = OGS_PDP_EUA_IETF_IPV6;
break;
case OGS_PDU_SESSION_TYPE_IPV4V6:
if (ip->ipv4 && ip->ipv6) {
eua->both.addr = ip->addr;
memcpy(eua->both.addr6, ip->addr6, OGS_IPV6_LEN);
*eua_len = 2 + OGS_IPV4_LEN + OGS_IPV6_LEN;
} else if (ip->ipv4) {
eua->addr = ip->addr;
*eua_len = 2 + OGS_IPV4_LEN;
} else if (ip->ipv6) {
memcpy(eua->addr6, ip->addr6, OGS_IPV6_LEN);
*eua_len = 2 + OGS_IPV6_LEN;
} else {
ogs_error("EUA type IPv4 but no IPv4 nor IPv6 address available");
return OGS_ERROR;
}
eua->type = OGS_PDP_EUA_IETF_IPV4V6;
break;
default:
ogs_error("Unexpected session type");
return OGS_ERROR;
}
return OGS_OK;
}
/* 3GPP TS 23.401 Table E.3 */
int ogs_gtp1_qos_profile_to_qci(const ogs_gtp1_qos_profile_decoded_t *decoded,
uint8_t *qci)
{
ogs_assert(decoded);
ogs_assert(qci);
if (!decoded->data_octet6_to_13_present) {
/* traffic class not present, take QCI 9 as default */
*qci = 9;
return OGS_OK;
}
switch (decoded->qos_profile.data.traffic_class) {
case OGS_GTP1_QOS_TRAFFIC_CLASS_CONVERSATIONAL:
if (decoded->qos_profile.data.source_statistics_descriptor == OGS_GTP1_QOS_SRC_STATS_DESC_SPEECH)
*qci = 1;
else if (decoded->dec_transfer_delay >= 150)
*qci = 2;
else
*qci = 3;
break;
case OGS_GTP1_QOS_TRAFFIC_CLASS_STREAMING:
*qci = 4;
break;
case OGS_GTP1_QOS_TRAFFIC_CLASS_INTERACTIVE:
switch (decoded->qos_profile.data.traffic_handling_priority) {
case 1:
*qci = decoded->qos_profile.data.signalling_indication ? 5 : 6;
break;
case 2:
*qci = 7;
break;
case 3:
*qci = 8;
break;
default:
*qci = 9;
}
break;
case OGS_GTP1_QOS_TRAFFIC_CLASS_SUBSCRIBED:
case OGS_GTP1_QOS_TRAFFIC_CLASS_BACKGROUND:
default:
*qci = 9;
}
return OGS_OK;
}