open5gs/lib/gtp/v1/types.c

716 lines
25 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) 2019 by Sukchan Lee <acetcom@gmail.com>
* 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"
/* 7.7.51 User Location Information (ULI) */
int16_t ogs_gtp1_parse_uli(ogs_gtp1_uli_t *uli, ogs_tlv_octet_t *octet)
{
ogs_gtp1_uli_t *source = (ogs_gtp1_uli_t *)octet->data;
int16_t size = 0;
ogs_assert(uli);
ogs_assert(octet);
memset(uli, 0, sizeof(ogs_gtp1_uli_t));
uli->geo_loc_type = source->geo_loc_type;
size++;
switch (uli->geo_loc_type) {
case OGS_GTP1_GEO_LOC_TYPE_CGI:
ogs_assert(size + sizeof(uli->cgi) <= octet->len);
memcpy(&uli->cgi,
(unsigned char *)octet->data + size, sizeof(uli->cgi));
uli->cgi.lac = be16toh(uli->cgi.lac);
uli->cgi.ci = be16toh(uli->cgi.ci);
size += sizeof(uli->cgi);
break;
case OGS_GTP1_GEO_LOC_TYPE_SAI:
ogs_assert(size + sizeof(uli->sai) <= octet->len);
memcpy(&uli->sai,
(unsigned char *)octet->data + size, sizeof(uli->sai));
uli->sai.lac = be16toh(uli->sai.lac);
uli->sai.sac = be16toh(uli->sai.sac);
size += sizeof(uli->sai);
break;
case OGS_GTP1_GEO_LOC_TYPE_RAI:
ogs_assert(size + sizeof(uli->rai) <= octet->len);
memcpy(&uli->rai,
(unsigned char *)octet->data + size, sizeof(uli->rai));
uli->rai.lac = be16toh(uli->rai.lac);
uli->rai.rac = be16toh(uli->rai.rac); //FIXME: Only the first octet (10) contains the RAC and the second octet (11) is coded as "11111111"
size += sizeof(uli->rai);
break;
default:
ogs_warn("Unknown Geographic Location Type 0x%x in User Location Information IE",
uli->geo_loc_type);
return 0;
}
ogs_assert(size == octet->len);
return size;
}
int16_t ogs_gtp1_build_uli(
ogs_tlv_octet_t *octet, ogs_gtp1_uli_t *uli, void *data, int data_len)
{
ogs_gtp1_uli_t target;
int16_t size = 0;
ogs_assert(uli);
ogs_assert(octet);
ogs_assert(data);
ogs_assert(data_len);
octet->data = data;
memcpy(&target, uli, sizeof(ogs_gtp1_uli_t));
ogs_assert(size + sizeof(target.geo_loc_type) <= data_len);
memcpy((unsigned char *)octet->data + size,
&target.geo_loc_type, sizeof(target.geo_loc_type));
size += sizeof(target.geo_loc_type);
if (target.geo_loc_type == OGS_GTP1_GEO_LOC_TYPE_CGI) {
ogs_assert(size + sizeof(target.cgi) <= data_len);
target.cgi.lac = htobe16(target.cgi.lac);
target.cgi.ci = htobe16(target.cgi.ci);
memcpy((unsigned char *)octet->data + size,
&target.cgi, sizeof(target.cgi));
size += sizeof(target.cgi);
}
if (target.geo_loc_type == OGS_GTP1_GEO_LOC_TYPE_SAI) {
ogs_assert(size + sizeof(target.sai) <= data_len);
target.sai.lac = htobe16(target.sai.lac);
target.sai.sac = htobe16(target.sai.sac);
memcpy((unsigned char *)octet->data + size,
&target.sai, sizeof(target.sai));
size += sizeof(target.sai);
}
if (target.geo_loc_type == OGS_GTP1_GEO_LOC_TYPE_RAI) {
ogs_assert(size + sizeof(target.rai) <= data_len);
target.rai.lac = htobe16(target.rai.lac);
target.rai.rac = htobe16(target.rai.rac); //FIXME: Only the first octet (10) contains the RAC and the second octet (11) is coded as "11111111"
memcpy((unsigned char *)octet->data + size,
&target.rai, sizeof(target.rai));
size += sizeof(target.rai);
}
octet->len = size;
return octet->len;
}
static uint32_t dec_mbr_kbps(uint8_t mbr_byte, const uint8_t *extended_mbr_byte, const uint8_t *extended2_mbr_byte)
{
uint8_t mbr, embr1, embr2;
mbr = mbr_byte;
embr1 = extended_mbr_byte ? *extended_mbr_byte : 0;
embr2 = extended2_mbr_byte ? *extended2_mbr_byte : 0;
if (mbr == 0)
return 0;
if (mbr == 0xff)
return UINT32_MAX;
if (mbr == 0xfe) { /* Check extended field */
if (extended_mbr_byte == NULL || embr1 == 0)
return 8640;
if (embr1 == 0xfa) { /* Check extended2 field */
if (extended2_mbr_byte == NULL || embr2 == 0)
return 256 * 1000;
if (embr2 == 0xf6)
return 10 * 1000 * 1000; /* TODO: check "extended quality of service" IE */
if (embr2 >= 0xa2 && embr2 <= 0xf6)
return (1500 + (embr2 - (0xa2 - 1)) * 100) * 1000;
if (embr2 >= 0x3e && embr2 <= 0xa1)
return (500 + (embr2 - (0x3e - 1)) * 10) * 1000;
return (256 + embr2 * 4) * 1000;
}
if (embr1 >= 0xbb && embr1 <= 0xfa)
return (128 + (embr1 - (0xbb - 1)) * 2) * 1000;
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
if (embr1 >= 0x4b && embr1 <= 0xba)
return (16 + (embr1 - (0x4b - 1)) * 1) * 1000;
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
return 8600 + embr1 * 100;
}
if (mbr & 0x80) {
mbr &= ~0x80;
return 576 + mbr_byte * 64;
}
if (mbr & 0x40) {
mbr &= ~0x40;
return 64 + mbr * 8;
}
return mbr;
}
static uint16_t dec_transfer_delay_ms(uint8_t transfer_delay_byte)
{
transfer_delay_byte &= 0x3f; /* 6 bits */
if (transfer_delay_byte <= 0x0f)
return transfer_delay_byte;
if (transfer_delay_byte <= 0x1f)
return 200 + (transfer_delay_byte - 0x10) * 50;
return 1000 + (transfer_delay_byte - 0x20) * 100;
}
/* TS 29.060 7.7.34 Quality of Service (QoS) Profile */
/* TS 24.008 10.5.6.5 Quality of service */
int16_t ogs_gtp1_parse_qos_profile(
ogs_gtp1_qos_profile_decoded_t *decoded, const ogs_tlv_octet_t *octet)
{
ogs_gtp1_qos_profile_t *source = (ogs_gtp1_qos_profile_t *)octet->data;
ogs_assert(decoded);
ogs_assert(octet);
memset(decoded, 0, sizeof(ogs_gtp1_qos_profile_decoded_t));
switch (octet->len) {
case 21: /* ARP + octet 3 + octet 3-22 */
decoded->bit_rate_uplink_extended2_present = true;
OGS_GNUC_FALLTHROUGH;
case 19: /* ARP + octet 3 + octet 3-20 */
decoded->bit_rate_downlink_extended2_present = true;
OGS_GNUC_FALLTHROUGH;
case 17: /* ARP + octet 3 + octet 3-18 */
decoded->bit_rate_uplink_extended_present = true;
OGS_GNUC_FALLTHROUGH;
case 15: /* ARP + octet 3 + octet 3-16 */
decoded->bit_rate_downlink_extended_present = true;
OGS_GNUC_FALLTHROUGH;
case 13: /* ARP + octet 3-14 */
decoded->data_octet14_present = true;
OGS_GNUC_FALLTHROUGH;
case 12: /* ARP + octet 3-13 */
decoded->data_octet6_to_13_present = true;
OGS_GNUC_FALLTHROUGH;
case 4: /* ARP + octet 3 + octet 4 + octet 5 */
break;
default:
ogs_warn("Qos Profile wrong length %u", octet->len);
return -1;
}
memcpy(&decoded->qos_profile, source, octet->len);
/* Calculate resulting MBRs in kbps: */
if (decoded->data_octet6_to_13_present) {
decoded->dec_transfer_delay = dec_transfer_delay_ms(source->data.transfer_delay);
decoded->dec_mbr_kbps_dl = dec_mbr_kbps(
source->data.max_bit_rate_downlink,
decoded->bit_rate_downlink_extended_present ?
&source->data.extended.max_bit_rate_downlink : NULL,
decoded->bit_rate_downlink_extended2_present ?
&source->data.extended2.max_bit_rate_downlink : NULL);
decoded->dec_mbr_kbps_ul = dec_mbr_kbps(
source->data.max_bit_rate_uplink,
decoded->bit_rate_uplink_extended_present ?
&source->data.extended.max_bit_rate_uplink : NULL,
decoded->bit_rate_uplink_extended2_present ?
&source->data.extended2.max_bit_rate_uplink : NULL);
/* GBR is encoded the same way as MBR: */
decoded->dec_gbr_kbps_dl = dec_mbr_kbps(
source->data.guaranteed_bit_rate_downlink,
decoded->bit_rate_downlink_extended_present ?
&source->data.extended.guaranteed_bit_rate_downlink : NULL,
decoded->bit_rate_downlink_extended2_present ?
&source->data.extended2.guaranteed_bit_rate_downlink : NULL);
decoded->dec_gbr_kbps_ul = dec_mbr_kbps(
source->data.guaranteed_bit_rate_uplink,
decoded->bit_rate_uplink_extended_present ?
&source->data.extended.guaranteed_bit_rate_uplink : NULL,
decoded->bit_rate_uplink_extended2_present ?
&source->data.extended2.guaranteed_bit_rate_uplink : NULL);
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
}
return octet->len;
}
static uint8_t enc_transfer_delay_ms(uint16_t transfer_delay_ms)
{
if (transfer_delay_ms >= 4000)
return 0x3e;
if (transfer_delay_ms >= 1000) {
transfer_delay_ms -= 1000;
return 0x20 + (transfer_delay_ms / 100);
}
if (transfer_delay_ms >= 200) {
transfer_delay_ms -= 200;
return 0x10 + (transfer_delay_ms / 50);
}
if (transfer_delay_ms > 150)
transfer_delay_ms = 150;
if (transfer_delay_ms >= 10)
return transfer_delay_ms / 10;
return 1; /* 0 is "Reserved" Network->MS */
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
}
#define CHECK_EXT1 0xfe
#define CHECK_EXT2 0xfa
static uint32_t enc_mbr_kbps(uint32_t mbr_kbps, uint8_t *mbr_byte, uint8_t *extended_mbr_byte, uint8_t *extended2_mbr_byte)
{
/* up to EXT2 byte: */
if (mbr_kbps > 10*1000*1000) {
*extended2_mbr_byte = 0xf6; /* TODO: need to set the real value somewhere else */
goto ret_check_ext2;
}
if (mbr_kbps >= 1600*1000) {
mbr_kbps -= 1500*1000;
*extended2_mbr_byte = 0xa1 + mbr_kbps/(100*1000);
goto ret_check_ext2;
}
if (mbr_kbps >= 510*1000) {
mbr_kbps -= 500*1000;
*extended2_mbr_byte = 0x2d + mbr_kbps/(10*1000);
goto ret_check_ext2;
}
if (mbr_kbps >= 260*1000) {
mbr_kbps -= 256*1000;
*extended2_mbr_byte = 0x00 + mbr_kbps/(4*1000);
goto ret_check_ext2;
}
/* up to EXT1 byte: */
if (mbr_kbps >= 130*1000) {
mbr_kbps -= 128*1000;
*extended_mbr_byte = 0xba + mbr_kbps/(2*1000);
goto ret_check_ext1;
}
if (mbr_kbps >= 17*1000) {
mbr_kbps -= 16*1000;
*extended_mbr_byte = 0x4a + mbr_kbps/(1*1000);
goto ret_check_ext1;
}
if (mbr_kbps >= 8700) {
mbr_kbps -= 8600;
*extended_mbr_byte = 0x00 + mbr_kbps/(100);
goto ret_check_ext1;
}
/* Only MBR byte: */
if (mbr_kbps >= 576) {
mbr_kbps -= 576;
*mbr_byte = 0x80 + mbr_kbps/(64);
goto ret_mbr;
}
if (mbr_kbps >= 64) {
mbr_kbps -= 64;
*mbr_byte = 0x40 + mbr_kbps/(8);
goto ret_mbr;
}
if (mbr_kbps > 0) {
*mbr_byte = mbr_kbps;
goto ret_mbr;
}
/* if (mbr_kpbs == 0) */
*mbr_byte = 0xff;
goto ret_mbr;
ret_check_ext2:
*extended_mbr_byte = CHECK_EXT2;
*mbr_byte = CHECK_EXT1;
return 2;
ret_check_ext1:
*extended2_mbr_byte = 0;
*mbr_byte = CHECK_EXT1;
return 1;
ret_mbr:
*extended2_mbr_byte = 0;
*extended_mbr_byte = 0;
return 0;
}
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)
{
ogs_gtp1_qos_profile_t *target;
int mbr_extended_dl, mbr_extended_ul;
int gbr_extended_dl, gbr_extended_ul;
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 extended_dl, extended_ul;
ogs_assert(octet);
ogs_assert(data);
ogs_assert((size_t)data_len >= sizeof(ogs_gtp1_qos_profile_t));
octet->data = data;
target = (ogs_gtp1_qos_profile_t *)octet->data;
/* First, copy the encoded buffer as it is: */
memcpy(target, &decoded->qos_profile, sizeof(ogs_gtp1_qos_profile_t));
/* Avoid setting Traffic Handling to 0=Reserved even if ignored based on
* Interactive/Background Traffic Class: */
if (target->data.traffic_handling_priority == 0)
target->data.traffic_handling_priority = 1;
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
/* Then, encode in the target position the decoded-provided fields: */
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
if (decoded->data_octet6_to_13_present)
target->data.transfer_delay = enc_transfer_delay_ms(decoded->dec_transfer_delay);
mbr_extended_dl = enc_mbr_kbps(decoded->dec_mbr_kbps_dl,
&target->data.max_bit_rate_downlink,
&target->data.extended.max_bit_rate_downlink,
&target->data.extended2.max_bit_rate_downlink);
mbr_extended_ul = enc_mbr_kbps(decoded->dec_mbr_kbps_ul,
&target->data.max_bit_rate_uplink,
&target->data.extended.max_bit_rate_uplink,
&target->data.extended2.max_bit_rate_uplink);
/* GBR is encoded the same way as MBR: */
gbr_extended_dl = enc_mbr_kbps(decoded->dec_gbr_kbps_dl,
&target->data.guaranteed_bit_rate_downlink,
&target->data.extended.guaranteed_bit_rate_downlink,
&target->data.extended2.guaranteed_bit_rate_downlink);
gbr_extended_ul = enc_mbr_kbps(decoded->dec_gbr_kbps_ul,
&target->data.guaranteed_bit_rate_uplink,
&target->data.extended.guaranteed_bit_rate_uplink,
&target->data.extended2.guaranteed_bit_rate_uplink);
extended_dl = ogs_max(mbr_extended_dl, gbr_extended_dl);
extended_ul = ogs_max(mbr_extended_ul, gbr_extended_ul);
/* Finally, set len based on the required octets to encode the fields: */
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
if (extended_ul == 2)
octet->len = 21;
else if (extended_dl == 2)
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
octet->len = 19;
else if (extended_ul == 1)
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
octet->len = 17;
else if (extended_dl == 1)
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
octet->len = 15;
else if (decoded->data_octet14_present)
octet->len = 13;
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
else if (decoded->data_octet6_to_13_present)
octet->len = 12;
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
else
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;
uint16_t val16;
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 |
(decoded->sec_mode == OGS_GTP1_SEC_MODE_USED_CIPHER_VALUE_UMTS_KEY_AND_QUINTUPLETS ?
decoded->used_cipher & 0x07 : 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(2);
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);
if (decoded->ms_network_capability_len != 0) {
/* MS Network Capability Length */
CHECK_SPACE_ERR(1 + decoded->ms_network_capability_len);
*ptr++ = decoded->ms_network_capability_len;
memcpy(ptr, &decoded->ms_network_capability, decoded->ms_network_capability_len);
ptr += decoded->ms_network_capability_len;
} else {
CHECK_SPACE_ERR(1);
*ptr++ = 0;
}
if (decoded->imeisv_len != 0) {
/* Container Len */
CHECK_SPACE_ERR(2);
val16 = htobe16(2 + decoded->imeisv_len);
memcpy(ptr, &val16, 2);
ptr += 2;
/* Container (Mobile Identity IMEISV), TS 29.060 Table 47A */
CHECK_SPACE_ERR(2 + decoded->imeisv_len);
*ptr++ = 0x23;
*ptr++ = decoded->imeisv_len; /* Length of mobile identity contents */
memcpy(ptr, &decoded->imeisv[0], decoded->imeisv_len);
ptr += decoded->imeisv_len;
} else {
/* Container Len */
CHECK_SPACE_ERR(2);
*ptr++ = 0;
*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)
{
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
}