Files
openairinterface5g/openair-cn/S11/s11_ie_formatter.c
T
Lionel Gauthier 059a0a3fdc astyle --recursive --indent=spaces=2 --style=kr --indent-col1-comments --break-blocks --convert-tabs --max-code-length=200
This is done for better merging branch/LG_PRE_RELEASE_0.3 into trunk (same process is applied on this branch)

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@7073 818b1a75-f10b-46b9-bf7c-635c3b92a50f
2015-04-09 09:29:12 +00:00

1165 lines
29 KiB
C

/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
*******************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include "assertions.h"
#include "conversions.h"
#include "sgw_lite_messages_types.h"
#include "NwGtpv2c.h"
#include "NwGtpv2cIe.h"
#include "NwGtpv2cMsg.h"
#include "NwGtpv2cMsgParser.h"
#include "s11_common.h"
#include "s11_ie_formatter.h"
NwRcT s11_imsi_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
Imsi_t *imsi;
uint8_t i;
uint8_t mask = 0x0F;
uint8_t imsi_length = 2 * ieLength;
DevAssert(arg != NULL);
imsi = (Imsi_t *)arg;
for (i = 0; i < ieLength * 2; i++) {
if (mask == 0x0F) {
imsi->digit[i] = (ieValue[i / 2] & (mask));
} else {
imsi->digit[i] = (ieValue[i / 2] & (mask)) >> 4;
}
imsi->digit[i] += '0';
mask = ~mask;
}
if (imsi->digit[imsi_length - 1] == (0x0f + '0')) {
imsi->digit[imsi_length - 1] = 0;
imsi_length--;
}
imsi->length = imsi_length;
S11_DEBUG("\t- IMSI length %d\n", imsi->length);
S11_DEBUG("\t- value %*s\n", imsi->length, imsi->digit);
return NW_OK;
}
int s11_imsi_ie_set(NwGtpv2cMsgHandleT *msg, const Imsi_t *imsi)
{
uint8_t *temp = NULL;
uint8_t imsi_length, i;
NwRcT rc;
DevAssert(msg != NULL);
DevAssert(imsi != NULL);
/* In case of odd/even imsi */
imsi_length = imsi->length % 2 == 0 ? imsi->length / 2 : imsi->length / 2 + 1;
temp = calloc(imsi_length, sizeof(uint8_t));
DevAssert(temp != NULL);
for (i = 0; i < imsi->length; i++) {
temp[i / 2] |= ((imsi->digit[i] - '0') & 0x0F) << (i % 2 ? 4 : 0);
}
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_IMSI, imsi_length, 0, temp);
DevAssert(NW_OK == rc);
free(temp);
return 0;
}
NwRcT s11_msisdn_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
Msisdn_t *msisdn;
uint8_t i;
uint8_t mask = 0x0F;
uint8_t msisdn_length = 2 * ieLength;
DevAssert(arg != NULL);
msisdn = (Msisdn_t *)arg;
for (i = 0; i < ieLength * 2; i++) {
if (mask == 0x0F) {
msisdn->digit[i] = (ieValue[i / 2] & (mask));
} else {
msisdn->digit[i] = (ieValue[i / 2] & (mask)) >> 4;
}
msisdn->digit[i] += '0';
mask = ~mask;
}
if (msisdn->digit[msisdn_length - 1] == (0x0f + '0')) {
msisdn->digit[msisdn_length - 1] = 0;
msisdn_length--;
}
msisdn->length = msisdn_length;
S11_DEBUG("\t- MSISDN length %d\n", msisdn->length);
S11_DEBUG("\t- value %*s\n", msisdn->length, (char *)msisdn->digit);
return NW_OK;
}
NwRcT s11_mei_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
Mei_t *mei = (Mei_t *)arg;
DevAssert(mei != NULL);
return NW_OK;
}
NwRcT s11_pdn_type_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
pdn_type_t *pdn_type = (pdn_type_t *)arg;
DevAssert(pdn_type != NULL);
if (*ieValue == 1) {
/* Only IPv4 */
*pdn_type = IPv4;
} else if (*ieValue == 2) {
/* Only IPv6 */
*pdn_type = IPv6;
} else if (*ieValue == 3) {
/* IPv4 and/or IPv6 */
*pdn_type = IPv4_AND_v6;
} else {
S11_ERROR("Received unknown value for PDN Type: %u\n", *ieValue);
return NW_GTPV2C_IE_INCORRECT;
}
S11_DEBUG("\t- PDN type %u\n", *pdn_type);
return NW_OK;
}
int s11_pdn_type_ie_set(NwGtpv2cMsgHandleT *msg, const pdn_type_t *pdn_type)
{
NwRcT rc;
uint8_t value;
DevAssert(pdn_type != NULL);
DevAssert(msg != NULL);
switch (*pdn_type) {
case IPv4:
value = 1;
break;
case IPv6:
value = 2;
break;
case IPv4_AND_v6:
case IPv4_OR_v6:
value = 3;
break;
default:
S11_ERROR("Invalid PDN type received: %d\n", *pdn_type);
return -1;
}
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_PDN_TYPE, 1, 0, (NwU8T*)&value);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_rat_type_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
rat_type_t *rat_type = (rat_type_t *)arg;
DevAssert(rat_type != NULL);
switch (*ieValue) {
case 1:
*rat_type = RAT_UTRAN;
break;
case 2:
*rat_type = RAT_GERAN;
break;
case 3:
*rat_type = RAT_WLAN;
break;
case 4:
*rat_type = RAT_GAN;
break;
case 5:
*rat_type = RAT_HSPA_EVOLUTION;
break;
case 6:
*rat_type = RAT_EUTRAN;
break;
default:
S11_ERROR("Can't map GTP RAT type %u to EPC definition\n"
"\tCheck TS.29.274 #8.17 for possible values\n", *ieValue);
return NW_GTPV2C_IE_INCORRECT;
}
S11_DEBUG("\t- RAT type (%d): %d\n", *ieValue, *rat_type);
return NW_OK;
}
int s11_rat_type_ie_set(NwGtpv2cMsgHandleT *msg, const rat_type_t *rat_type)
{
NwRcT rc;
uint8_t value;
DevAssert(rat_type != NULL);
DevAssert(msg != NULL);
switch (*rat_type) {
case RAT_UTRAN:
value = 1;
break;
case RAT_GERAN:
value = 2;
break;
case RAT_WLAN:
value = 3;
break;
case RAT_GAN:
value = 4;
break;
case RAT_HSPA_EVOLUTION:
value = 5;
break;
case RAT_EUTRAN:
value = 6;
break;
default:
S11_ERROR("Can't map RAT type %d to GTP RAT type\n"
"\tCheck TS.29.274 #8.17 for possible values\n", *rat_type);
return -1;
}
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_RAT_TYPE, 1, 0, (NwU8T*)&value);
DevAssert(NW_OK == rc);
return 0;
}
int s11_ebi_ie_set(NwGtpv2cMsgHandleT *msg, const unsigned ebi)
{
NwRcT rc;
uint8_t value = 0;
value = ebi & 0x0F;
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_EBI, 1, 0,
&value);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_ebi_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
uint8_t *ebi = (uint8_t *)arg;
DevAssert(ebi != NULL);
*ebi = ieValue[0] & 0x0F;
S11_DEBUG("\t- EBI %u\n", *ebi);
return NW_OK;
}
NwRcT s11_cause_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
SGWCause_t *cause = (SGWCause_t *)arg;
DevAssert(cause != NULL);
*cause = ieValue[0];
S11_DEBUG("\t- Cause %u\n", *cause);
return NW_OK;
}
int s11_cause_ie_set(NwGtpv2cMsgHandleT *msg,
const gtp_cause_t *cause)
{
NwRcT rc;
uint8_t value[6];
DevAssert(msg != NULL);
DevAssert(cause != NULL);
value[0] = cause->cause_value;
value[1] = ((cause->pce & 0x1) << 2) | ((cause->bce & 0x1) << 1) | (cause->cs & 0x1);
if (cause->offending_ie_type != 0) {
value[2] = cause->offending_ie_type;
value[3] = (cause->offending_ie_length & 0xFF00) >> 8;
value[4] = cause->offending_ie_length & 0x00FF;
value[5] = cause->offending_ie_instance & 0x0F;
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_CAUSE, 6, 0, value);
} else {
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_CAUSE, 2, 0, value);
}
DevAssert(NW_OK == rc);
return rc == NW_OK ? 0 : -1;
}
NwRcT s11_bearer_context_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
bearer_to_create_t *bearer_to_create = (bearer_to_create_t *)arg;
uint8_t read = 0;
NwRcT rc;
DevAssert(bearer_to_create != NULL);
while (ieLength > read) {
NwGtpv2cIeTlvT *ie_p;
ie_p = (NwGtpv2cIeTlvT*)&ieValue[read];
switch (ie_p->t) {
case NW_GTPV2C_IE_EBI:
rc = s11_ebi_ie_get(ie_p->t, ie_p->l, ie_p->i,
&ieValue[read + sizeof(NwGtpv2cIeTlvT)],
&bearer_to_create->eps_bearer_id);
DevAssert(NW_OK == rc);
break;
case NW_GTPV2C_IE_BEARER_LEVEL_QOS:
break;
default:
S11_ERROR("Received unexpected IE %u\n", ie_p->t);
return NW_GTPV2C_IE_INCORRECT;
}
read += (ntohs(ie_p->l) + sizeof(NwGtpv2cIeTlvT));
}
return NW_OK;
}
int s11_bearer_context_to_create_ie_set(
NwGtpv2cMsgHandleT *msg, const bearer_to_create_t *bearer_to_create)
{
NwRcT rc;
DevAssert(msg != NULL);
DevAssert(bearer_to_create != NULL);
/* Start section for grouped IE: bearer context to create */
rc = nwGtpv2cMsgGroupedIeStart(*msg, NW_GTPV2C_IE_BEARER_CONTEXT,
NW_GTPV2C_IE_INSTANCE_ZERO);
DevAssert(NW_OK == rc);
s11_ebi_ie_set(msg, bearer_to_create->eps_bearer_id);
/* End section for grouped IE: bearer context to create */
rc = nwGtpv2cMsgGroupedIeEnd(*msg);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_bearer_context_to_modifiy_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
bearer_context_to_modify_t *bearer_to_modify = (bearer_context_to_modify_t *)arg;
uint8_t read = 0;
NwRcT rc;
DevAssert(bearer_to_modify != NULL);
while (ieLength > read) {
NwGtpv2cIeTlvT *ie_p;
ie_p = (NwGtpv2cIeTlvT*)&ieValue[read];
switch (ie_p->t) {
case NW_GTPV2C_IE_EBI:
rc = s11_ebi_ie_get(ie_p->t, ie_p->l, ie_p->i,
&ieValue[read + sizeof(NwGtpv2cIeTlvT)],
&bearer_to_modify->eps_bearer_id);
DevAssert(NW_OK == rc);
break;
case NW_GTPV2C_IE_FTEID:
rc = s11_fteid_ie_get(ie_p->t, ie_p->l, ie_p->i,
&ieValue[read + sizeof(NwGtpv2cIeTlvT)],
&bearer_to_modify->s1_eNB_fteid);
break;
default:
S11_ERROR("Received unexpected IE %u\n", ie_p->t);
return NW_GTPV2C_IE_INCORRECT;
}
read += (ntohs(ie_p->l) + sizeof(NwGtpv2cIeTlvT));
}
return NW_OK;
}
NwRcT s11_bearer_context_created_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
bearer_context_created_t *bearer_created = (bearer_context_created_t *)arg;
uint8_t read = 0;
NwRcT rc;
DevAssert(bearer_created != NULL);
while (ieLength > read) {
NwGtpv2cIeTlvT *ie_p;
ie_p = (NwGtpv2cIeTlvT*)&ieValue[read];
switch (ie_p->t) {
case NW_GTPV2C_IE_EBI:
rc = s11_ebi_ie_get(ie_p->t, ie_p->l, ie_p->i,
&ieValue[read + sizeof(NwGtpv2cIeTlvT)],
&bearer_created->eps_bearer_id);
DevAssert(NW_OK == rc);
break;
case NW_GTPV2C_IE_FTEID:
rc = s11_fteid_ie_get(ie_p->t, ie_p->l, ie_p->i,
&ieValue[read + sizeof(NwGtpv2cIeTlvT)],
&bearer_created->s1u_sgw_fteid);
break;
case NW_GTPV2C_IE_CAUSE:
rc = s11_cause_ie_get(ie_p->t, ie_p->l, ie_p->i,
&ieValue[read + sizeof(NwGtpv2cIeTlvT)],
&bearer_created->cause);
break;
default:
S11_ERROR("Received unexpected IE %u\n", ie_p->t);
return NW_GTPV2C_IE_INCORRECT;
}
read += (ntohs(ie_p->l) + sizeof(NwGtpv2cIeTlvT));
}
return NW_OK;
}
int s11_bearer_context_created_ie_set(
NwGtpv2cMsgHandleT *msg, const bearer_context_created_t *bearer)
{
NwRcT rc;
DevAssert(msg != NULL);
DevAssert(bearer != NULL);
/* Start section for grouped IE: bearer context created */
rc = nwGtpv2cMsgGroupedIeStart(*msg, NW_GTPV2C_IE_BEARER_CONTEXT,
NW_GTPV2C_IE_INSTANCE_ZERO);
DevAssert(NW_OK == rc);
s11_ebi_ie_set(msg, bearer->eps_bearer_id);
rc = nwGtpv2cMsgAddIeCause(*msg, NW_GTPV2C_IE_INSTANCE_ZERO, bearer->cause,
0, 0, 0);
DevAssert(NW_OK == rc);
rc = nwGtpv2cMsgAddIeFteid(*msg, NW_GTPV2C_IE_INSTANCE_ZERO,
bearer->s1u_sgw_fteid.interface_type,
bearer->s1u_sgw_fteid.teid,
bearer->s1u_sgw_fteid.ipv4 ? htonl(bearer->s1u_sgw_fteid.ipv4_address) : 0,
bearer->s1u_sgw_fteid.ipv6 ? (NwU8T*)bearer->s1u_sgw_fteid.ipv6_address : NULL);
DevAssert(NW_OK == rc);
/* End section for grouped IE: bearer context created */
rc = nwGtpv2cMsgGroupedIeEnd(*msg);
DevAssert(NW_OK == rc);
return 0;
}
/* This IE shall be included in the E-UTRAN initial attach,
* PDP Context Activation and UE Requested PDN connectivity procedures.
* This IE denotes the most stringent restriction as required
* by any already active bearer context. If there are no already active bearer
* contexts, this value is set to the least restrictive type.
*/
int s11_apn_restriction_ie_set(
NwGtpv2cMsgHandleT *msg, const uint8_t apn_restriction)
{
NwRcT rc;
DevAssert(msg != NULL);
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_APN_RESTRICTION, 1, 0,
(NwU8T *)&apn_restriction);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_serving_network_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
ServingNetwork_t *serving_net = (ServingNetwork_t *)arg;
DevAssert(serving_net != NULL);
serving_net->mcc[1] = (ieValue[0] & 0xF0) >> 4;
serving_net->mcc[0] = (ieValue[0] & 0x0F);
serving_net->mcc[2] = (ieValue[1] & 0x0F);
if ((ieValue[1] & 0xF0) == 0xF0) {
/* Two digits MNC */
serving_net->mnc[0] = 0;
serving_net->mnc[2] = (ieValue[2] & 0xF0) >> 4;
serving_net->mnc[1] = (ieValue[2] & 0x0F);
} else {
serving_net->mnc[0] = (ieValue[1] & 0xF0) >> 4;
serving_net->mnc[2] = (ieValue[2] & 0xF0) >> 4;
serving_net->mnc[1] = (ieValue[2] & 0x0F);
}
S11_DEBUG("\t- Serving network %d.%d\n",
serving_net->mcc[0] * 100 + serving_net->mcc[1] * 10
+ serving_net->mcc[2],
serving_net->mnc[0] * 100 + serving_net->mnc[1] * 10
+ serving_net->mnc[2]);
return NW_OK;
}
int s11_serving_network_ie_set(
NwGtpv2cMsgHandleT *msg,
const ServingNetwork_t *serving_network)
{
NwRcT rc;
uint8_t value[3];
DevAssert(msg != NULL);
DevAssert(serving_network != NULL);
/* MCC Decimal | MCC Hundreds */
value[0] = ((serving_network->mcc[1] & 0x0F) << 4) |
(serving_network->mcc[2] & 0x0F);
value[1] = serving_network->mcc[0] & 0x0F;
if ((serving_network->mnc[0] & 0xF) == 0xF) {
/* Only two digits */
value[1] |= 0xF0;
value[2] = ((serving_network->mnc[2] & 0x0F) << 4) |
(serving_network->mnc[1] & 0x0F);
} else {
value[1] |= (serving_network->mnc[2] & 0x0F) << 4;
value[2] = ((serving_network->mnc[1] & 0x0F) << 4) |
(serving_network->mnc[0] & 0x0F);
}
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_SERVING_NETWORK, 3, 0, value);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_fteid_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
uint8_t offset = 0;
FTeid_t *fteid = (FTeid_t *)arg;
DevAssert(fteid != NULL);
fteid->ipv4 = (ieValue[0] & 0x80) >> 7;
fteid->ipv6 = (ieValue[0] & 0x40) >> 6;
fteid->interface_type = ieValue[0] & 0x1F;
S11_DEBUG("\t- F-TEID type %d\n", fteid->interface_type);
/* Copy the TEID or GRE key */
fteid->teid = ntoh_int32_buf(&ieValue[1]);
S11_DEBUG("\t- TEID/GRE %08x\n", fteid->teid);
if (fteid->ipv4 == 1) {
/* IPv4 present: copy the 4 bytes */
memcpy(&fteid->ipv4_address, &ieValue[5], 4);
offset = 4;
S11_DEBUG("\t- IPv4 addr "IPV4_ADDR"\n",
IPV4_ADDR_FORMAT(fteid->ipv4_address));
}
if (fteid->ipv6 == 1) {
char ipv6_ascii[40];
/* IPv6 present: copy the 16 bytes
* WARNING: if Ipv4 is present, 4 bytes of offset should be applied
*/
memcpy(fteid->ipv6_address, &ieValue[5 + offset], 16);
inet_ntop(AF_INET6, fteid->ipv6_address, ipv6_ascii, 40);
S11_DEBUG("\t- IPv6 addr %s\n", ipv6_ascii);
}
return NW_OK;
}
NwRcT s11_paa_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
uint8_t offset = 0;
PAA_t *paa = (PAA_t *)arg;
DevAssert(paa != NULL);
paa->pdn_type = ieValue[0] & 0x07;
S11_DEBUG("\t- PAA type %d\n", paa->pdn_type);
if (paa->pdn_type & 0x2) {
char ipv6_ascii[40];
/* IPv6 present: copy the 16 bytes
* WARNING: if both ipv4 and ipv6 are present,
* 17 bytes of offset should be applied for ipv4
* NOTE: an ipv6 prefix length is prepend
* NOTE: in Rel.8 the prefix length has a default value of /64
*/
paa->ipv6_prefix_length = ieValue[1];
memcpy(paa->ipv6_address, &ieValue[2], 16);
inet_ntop(AF_INET6, paa->ipv6_address, ipv6_ascii, 40);
S11_DEBUG("\t- IPv6 addr %s/%u\n", ipv6_ascii, paa->ipv6_prefix_length);
}
if (paa->pdn_type == 3) {
offset = 17;
}
if (paa->pdn_type & 0x1) {
memcpy(paa->ipv4_address, &ieValue[1 + offset], 4);
S11_DEBUG("\t- IPv4 addr "IPV4_ADDR"\n",
paa->ipv4_address[0], paa->ipv4_address[1],
paa->ipv4_address[2], paa->ipv4_address[3]);
}
paa->pdn_type -= 1;
return NW_OK;
}
int s11_paa_ie_set(NwGtpv2cMsgHandleT *msg, const PAA_t *paa)
{
/* ipv4 address = 4 + ipv6 address = 16 + ipv6 prefix length = 1
* + pdn_type = 1
* = maximum of 22 bytes
*/
uint8_t temp[22];
uint8_t pdn_type;
uint8_t offset = 0;
NwRcT rc;
DevAssert(paa != NULL);
pdn_type = paa->pdn_type + 1;
temp[offset] = pdn_type;
offset++;
if (pdn_type & 0x2) {
/* If ipv6 or ipv4v6 present */
temp[1] = paa->ipv6_prefix_length;
memcpy(&temp[2], paa->ipv6_address, 16);
offset += 17;
}
if (pdn_type & 0x1) {
memcpy(&temp[offset], paa->ipv4_address, 4);
offset += 4;
}
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_PAA, offset, 0,
temp);
DevAssert(NW_OK == rc);
return 0;
}
/* The encoding of the APN shall follow the Name Syntax defined in RFC 2181,
* RFC 1035 and RFC 1123. The APN consists of one or more labels. Each label
* is coded as a one octet length field followed by that number of octets
* coded as 8 bit ASCII characters. Following RFC 1035 the labels shall consist
* only of the alphabetic characters (A-Z and a-z), digits (0-9)
* and the hyphen (-).
*/
NwRcT s11_apn_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
uint8_t read = 1;
uint8_t word_length;
char *apn = (char *)arg;
DevAssert(apn != NULL);
DevCheck(ieLength <= APN_MAX_LENGTH, ieLength, APN_MAX_LENGTH, 0);
word_length = ieValue[0];
while (read < ieLength) {
if (word_length > 0) {
apn[read - 1] = ieValue[read];
word_length--;
} else {
/* This is not an alphanumeric character */
word_length = ieValue[read];
/* Replace the length attribute by '.' */
apn[read - 1] = '.';
}
read ++;
}
apn[read - 1] = '\0';
S11_DEBUG("\t- APN %s\n", apn);
return NW_OK;
}
int s11_apn_ie_set(NwGtpv2cMsgHandleT *msg, const char *apn)
{
NwRcT rc;
uint8_t *value;
uint8_t apn_length;
uint8_t offset = 0;
uint8_t *last_size;
uint8_t word_length = 0;
DevAssert(apn != NULL);
DevAssert(msg != NULL);
apn_length = strlen(apn);
value = calloc(apn_length + 1, sizeof(uint8_t));
last_size = &value[0];
while (apn[offset]) {
/* We replace the . by the length of the word */
if (apn[offset] == '.') {
*last_size = word_length;
word_length = 0;
last_size = &value[offset + 1];
} else {
word_length++;
value[offset + 1] = apn[offset];
}
offset++;
}
*last_size = word_length;
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_APN, apn_length + 1, 0, value);
DevAssert(NW_OK == rc);
free(value);
return 0;
}
NwRcT s11_ambr_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
ambr_t *ambr = (ambr_t *)arg;
DevAssert(ambr != NULL);
ambr->br_ul = ntoh_int32_buf(&ieValue[0]);
ambr->br_dl = ntoh_int32_buf(&ieValue[4]);
S11_DEBUG("\t- AMBR UL %"PRIu64"\n", ambr->br_ul);
S11_DEBUG("\t- AMBR DL %"PRIu64"\n", ambr->br_dl);
return NW_OK;
}
NwRcT s11_uli_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
Uli_t *uli = (Uli_t *)arg;
DevAssert(uli != NULL);
uli->present = ieValue[0];
if (uli->present & ULI_CGI) {
}
return NW_OK;
}
int s11_bearer_qos_ie_set(NwGtpv2cMsgHandleT *msg, const BearerQOS_t *bearer_qos)
{
NwRcT rc;
uint8_t value[18];
DevAssert(msg != NULL);
DevAssert(bearer_qos != NULL);
value[0] = (bearer_qos->pci << 6) | (bearer_qos->pl << 2) | (bearer_qos->pvi);
value[1] = bearer_qos->qci;
/* TODO: check endianness */
memcpy(&value[2], &bearer_qos->mbr.br_ul, 4);
memcpy(&value[6], &bearer_qos->mbr.br_dl, 4);
memcpy(&value[10], &bearer_qos->gbr.br_ul, 4);
memcpy(&value[14], &bearer_qos->gbr.br_dl, 4);
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_BEARER_LEVEL_QOS, 18, 0, value);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_ip_address_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
gtp_ip_address_t *ip_address = (gtp_ip_address_t *)arg;
DevAssert(ip_address != NULL);
if (ieLength == 4) {
/* This is an IPv4 Address */
ip_address->present = GTP_IP_ADDR_v4;
memcpy(ip_address->address.v4, ieValue, 4);
} else if (ieLength == 16) {
/* This is an IPv6 Address */
ip_address->present = GTP_IP_ADDR_v6;
memcpy(ip_address->address.v6, ieValue, 16);
} else {
/* Length doesn't lie in possible values */
return NW_GTPV2C_IE_INCORRECT;
}
return NW_OK;
}
int s11_ip_address_ie_set(NwGtpv2cMsgHandleT *msg,
const gtp_ip_address_t *ip_address)
{
return 0;
}
NwRcT s11_delay_value_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
DelayValue_t *delay_value = (DelayValue_t *)arg;
DevAssert(arg != NULL);
if (ieLength != 1) {
return NW_GTPV2C_IE_INCORRECT;
}
*delay_value = ieValue[0];
S11_DEBUG("\t - Delay Value %u\n", *delay_value);
return NW_OK;
}
int s11_delay_value_ie_set(NwGtpv2cMsgHandleT *msg,
const DelayValue_t *delay_value)
{
uint8_t value;
NwRcT rc;
DevAssert(msg != NULL);
DevAssert(delay_value != NULL);
value = *delay_value;
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_DELAY_VALUE, 1, 0, (NwU8T*)&value);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_ue_time_zone_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
UETimeZone_t *ue_time_zone = (UETimeZone_t *)arg;
DevAssert(ue_time_zone != NULL);
if (ieLength != 2) {
return NW_GTPV2C_IE_INCORRECT;
}
ue_time_zone->time_zone = ieValue[0];
ue_time_zone->daylight_saving_time = ieValue[1] & 0x03;
S11_DEBUG("\t - Time Zone %u\n", ue_time_zone->time_zone);
S11_DEBUG("\t - Daylight SVT %u\n", ue_time_zone->daylight_saving_time);
return NW_OK;
}
int s11_ue_time_zone_ie_set(NwGtpv2cMsgHandleT *msg,
const UETimeZone_t *ue_time_zone)
{
uint8_t value[2];
NwRcT rc;
DevAssert(msg != NULL);
DevAssert(ue_time_zone != NULL);
value[0] = ue_time_zone->time_zone;
value[1] = ue_time_zone->daylight_saving_time;
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_UE_TIME_ZONE, 2, 0, value);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_target_identification_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
target_identification_t *target_identification = (target_identification_t *)arg;
DevAssert(target_identification != NULL);
target_identification->target_type = ieValue[0];
switch (target_identification->target_type) {
case TARGET_ID_RNC_ID: {
target_identification->target_id.rnc_id.lac = (ieValue[4] << 8) |
ieValue[5];
target_identification->target_id.rnc_id.rac = ieValue[6];
if (ieLength == 11) {
/* Extended RNC id */
target_identification->target_id.rnc_id.rnc_id = (ieValue[7] << 24) |
(ieValue[8] << 16) | (ieValue[9] << 8) | (ieValue[10]);
} else if (ieLength == 9) {
/* Normal RNC id */
target_identification->target_id.rnc_id.rnc_id = (ieValue[7] << 8) |
ieValue[8];
} else {
/* This case is not possible */
return NW_GTPV2C_IE_INCORRECT;
}
S11_DEBUG("\t\t- LAC 0x%04x\n", target_identification->target_id.rnc_id.lac);
S11_DEBUG("\t\t- RAC 0x%02x\n", target_identification->target_id.rnc_id.rac);
S11_DEBUG("\t\t- RNC 0x%08x\n", target_identification->target_id.rnc_id.rnc_id);
}
break;
case TARGET_ID_MACRO_ENB_ID: {
if (ieLength != 9) {
return NW_GTPV2C_IE_INCORRECT;
}
target_identification->target_id.macro_enb_id.enb_id = ((ieValue[4] & 0x0F) << 16) |
(ieValue[5] << 8) | ieValue[6];
target_identification->target_id.macro_enb_id.tac = (ieValue[7] << 8) | ieValue[8];
S11_DEBUG("\t\t- ENB Id 0x%06x\n", target_identification->target_id.macro_enb_id.enb_id);
S11_DEBUG("\t\t- TAC 0x%04x\n", target_identification->target_id.macro_enb_id.tac);
}
break;
case TARGET_ID_HOME_ENB_ID: {
if (ieLength != 10) {
return NW_GTPV2C_IE_INCORRECT;
}
target_identification->target_id.home_enb_id.enb_id = ((ieValue[4] & 0x0F) << 14) |
(ieValue[5] << 16) | (ieValue[6] << 8) | ieValue[7];
target_identification->target_id.home_enb_id.tac = (ieValue[8] << 8) | ieValue[9];
S11_DEBUG("\t\t- ENB Id 0x%07x\n", target_identification->target_id.home_enb_id.enb_id);
S11_DEBUG("\t\t- TAC 0x%04x\n", target_identification->target_id.home_enb_id.tac);
}
break;
default:
return NW_GTPV2C_IE_INCORRECT;
}
return NW_OK;
}
NwRcT s11_bearer_flags_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
bearer_flags_t *bearer_flags = (bearer_flags_t *)arg;
DevAssert(arg != NULL);
if (ieLength != 1) {
return NW_GTPV2C_IE_INCORRECT;
}
bearer_flags->ppc = ieValue[0] & 0x01;
bearer_flags->vb = ieValue[0] & 0x02;
return NW_OK;
}
int s11_bearer_flags_ie_set(NwGtpv2cMsgHandleT *msg,
const bearer_flags_t *bearer_flags)
{
NwRcT rc;
uint8_t value;
DevAssert(msg != NULL);
DevAssert(bearer_flags != NULL);
value = (bearer_flags->vb << 1) | bearer_flags->ppc;
rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_BEARER_FLAGS, 1, 0, (NwU8T*)&value);
DevAssert(NW_OK == rc);
return 0;
}
NwRcT s11_indication_flags_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
indication_flags_t *indication_flags = (indication_flags_t*)arg;
DevAssert(indication_flags != NULL);
if (ieLength < 3) {
return NW_GTPV2C_IE_INCORRECT;
}
*indication_flags = ieValue[0] | (ieValue[1] << 8) | (ieValue[2] << 16);
S11_DEBUG("\t- Indication Flags %06x\n", *indication_flags);
return NW_OK;
}
NwRcT s11_fqcsid_ie_get(
NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg)
{
FQ_CSID_t *fq_csid = (FQ_CSID_t *)arg;
DevAssert(fq_csid != NULL);
fq_csid->node_id_type = (ieValue[0] & 0xF0) >> 4;
S11_DEBUG("\t- FQ-CSID type %u\n", fq_csid->node_id_type);
/* NOTE: Values of Number of CSID other than 1 are only employed in the
* Delete PDN Connection Set Request and Response.
*/
if ((ieValue[0] & 0x0F) != 1) {
return NW_GTPV2C_IE_INCORRECT;
}
switch (fq_csid->node_id_type) {
case GLOBAL_UNICAST_IPv4: {
if (ieLength != 7) {
return NW_GTPV2C_IE_INCORRECT;
}
fq_csid->node_id.unicast_ipv4 = (ieValue[1] << 24) |
(ieValue[2] << 16) | (ieValue[3] << 8) | (ieValue[4]);
fq_csid->csid = (ieValue[5] << 8) | ieValue[6];
S11_DEBUG("\t- v4 address ["IPV4_ADDR"]\n",
IPV4_ADDR_FORMAT(fq_csid->node_id.unicast_ipv4));
}
break;
case GLOBAL_UNICAST_IPv6: {
char ipv6[40];
if (ieLength != 19) {
return NW_GTPV2C_IE_INCORRECT;
}
memcpy(fq_csid->node_id.unicast_ipv6, &ieValue[1], 16);
fq_csid->csid = (ieValue[17] << 8) | ieValue[18];
/* Convert the ipv6 to printable string */
inet_ntop(AF_INET6, fq_csid->node_id.unicast_ipv6, ipv6, 40);
S11_DEBUG("\t- v6 address [%s]\n", fq_csid->node_id.unicast_ipv6);
}
break;
default:
return NW_GTPV2C_IE_INCORRECT;
}
S11_DEBUG("\t- CSID 0x%04x\n", fq_csid->csid);
return NW_OK;
}