Files
openairinterface5g/openair-cn/S6A/s6a_subscription_data.c
T
Lionel Gauthier 26495e6a0a GPLv3
git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5552 818b1a75-f10b-46b9-bf7c-635c3b92a50f
2014-07-17 13:40:57 +00:00

398 lines
14 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 <stdint.h>
#include "common_types.h"
#include "s6a_defs.h"
#include "assertions.h"
static inline
int s6a_parse_subscriber_status(struct avp_hdr *hdr_sub_status,
subscriber_status_t *sub_status)
{
DevCheck(hdr_sub_status->avp_value->u32 < SS_MAX,
hdr_sub_status->avp_value->u32, SS_MAX, 0);
*sub_status = hdr_sub_status->avp_value->u32;
return 0;
}
static inline
int s6a_parse_msisdn(struct avp_hdr *hdr_msisdn, char *msisdn, uint8_t *length)
{
int ret;
DevCheck(hdr_msisdn->avp_value->os.len <= MSISDN_LENGTH,
hdr_msisdn->avp_value->os.len, MSISDN_LENGTH, 0);
if (hdr_msisdn->avp_value->os.len == 0)
return 0;
ret = sprintf(msisdn, "%*s", (int)hdr_msisdn->avp_value->os.len,
hdr_msisdn->avp_value->os.data);
*length = ret;
return 0;
}
static inline
int s6a_parse_network_access_mode(struct avp_hdr *hdr_network_am,
network_access_mode_t *access_mode)
{
DevCheck(hdr_network_am->avp_value->u32 < NAM_MAX &&
hdr_network_am->avp_value->u32 != NAM_RESERVED,
hdr_network_am->avp_value->u32, NAM_MAX, NAM_RESERVED);
*access_mode = hdr_network_am->avp_value->u32;
return 0;
}
static inline
int s6a_parse_access_restriction_data(struct avp_hdr *hdr_access_restriction,
access_restriction_t *access_restriction)
{
DevCheck(hdr_access_restriction->avp_value->u32 < ARD_MAX,
hdr_access_restriction->avp_value->u32, ARD_MAX, 0);
*access_restriction = hdr_access_restriction->avp_value->u32;
return 0;
}
static inline
int s6a_parse_bitrate(struct avp_hdr *hdr_bitrate, bitrate_t *bitrate)
{
*bitrate = hdr_bitrate->avp_value->u32;
return 0;
}
static inline
int s6a_parse_ambr(struct avp *avp_ambr, ambr_t *ambr)
{
struct avp *avp = NULL;
struct avp_hdr *hdr;
CHECK_FCT(fd_msg_browse(avp_ambr, MSG_BRW_FIRST_CHILD, &avp, NULL));
if (!avp) {
/* Child avps for ambr are mandatory */
return -1;
}
while(avp) {
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
switch(hdr->avp_code) {
case AVP_CODE_BANDWIDTH_UL:
CHECK_FCT(s6a_parse_bitrate(hdr, &ambr->br_ul));
break;
case AVP_CODE_BANDWIDTH_DL:
CHECK_FCT(s6a_parse_bitrate(hdr, &ambr->br_dl));
break;
default:
return -1;
}
/* Go to next AVP in the grouped AVP */
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL));
}
return 0;
}
static inline
int s6a_parse_all_apn_conf_inc_ind(struct avp_hdr *hdr, all_apn_conf_ind_t *ptr)
{
DevCheck(hdr->avp_value->u32 < ALL_APN_MAX,
hdr->avp_value->u32, ALL_APN_MAX, 0);
*ptr = hdr->avp_value->u32;
return 0;
}
static inline
int s6a_parse_pdn_type(struct avp_hdr *hdr, pdn_type_t *pdn_type)
{
DevCheck(hdr->avp_value->u32 < IP_MAX,
hdr->avp_value->u32, IP_MAX, 0);
*pdn_type = hdr->avp_value->u32;
return 0;
}
static inline
int s6a_parse_service_selection(struct avp_hdr *hdr_service_selection,
char *service_selection, int *length)
{
DevCheck(hdr_service_selection->avp_value->os.len <= APN_MAX_LENGTH,
hdr_service_selection->avp_value->os.len, APN_MAX_LENGTH, 0);
*length = sprintf(service_selection, "%*s",
(int)hdr_service_selection->avp_value->os.len,
hdr_service_selection->avp_value->os.data);
return 0;
}
static inline
int s6a_parse_qci(struct avp_hdr *hdr, qci_t *qci)
{
DevCheck(hdr->avp_value->u32 < QCI_MAX,
hdr->avp_value->u32, QCI_MAX, 0);
*qci = hdr->avp_value->u32;
return 0;
}
static inline
int s6a_parse_priority_level(struct avp_hdr *hdr, priority_level_t *priority_level)
{
DevCheck(hdr->avp_value->u32 <= PRIORITY_LEVEL_MAX &&
hdr->avp_value->u32 >= PRIORITY_LEVEL_MIN, hdr->avp_value->u32,
PRIORITY_LEVEL_MAX, PRIORITY_LEVEL_MIN);
*priority_level = (priority_level_t)hdr->avp_value->u32;
return 0;
}
static inline
int s6a_parse_pre_emp_capability(struct avp_hdr *hdr, pre_emp_capability_t *pre_emp_capability)
{
DevCheck(hdr->avp_value->u32 < PRE_EMPTION_CAPABILITY_MAX, hdr->avp_value->u32,
PRE_EMPTION_CAPABILITY_MAX, 0);
*pre_emp_capability = hdr->avp_value->u32;
return 0;
}
static inline
int s6a_parse_pre_emp_vulnerability(struct avp_hdr *hdr, pre_emp_vulnerability_t *pre_emp_vulnerability)
{
DevCheck(hdr->avp_value->u32 < PRE_EMPTION_VULNERABILITY_MAX, hdr->avp_value->u32,
PRE_EMPTION_VULNERABILITY_MAX, 0);
*pre_emp_vulnerability = hdr->avp_value->u32;
return 0;
}
static inline
int s6a_parse_allocation_retention_priority(struct avp *avp_arp,
allocation_retention_priority_t *ptr)
{
struct avp *avp = NULL;
struct avp_hdr *hdr;
/* If the Pre-emption-Capability AVP is not present in the
* Allocation-Retention-Priority AVP, the default value shall be
* PRE-EMPTION_CAPABILITY_DISABLED (1).
*/
ptr->pre_emp_capability = PRE_EMPTION_CAPABILITY_DISABLED;
/* If the Pre-emption-Vulnerability AVP is not present in the
* Allocation-Retention-Priority AVP, the default value shall be
* PRE-EMPTION_VULNERABILITY_ENABLED (0).
*/
ptr->pre_emp_vulnerability = PRE_EMPTION_VULNERABILITY_ENABLED;
CHECK_FCT(fd_msg_browse(avp_arp, MSG_BRW_FIRST_CHILD, &avp, NULL));
while(avp) {
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
switch(hdr->avp_code) {
case AVP_CODE_PRIORITY_LEVEL:
CHECK_FCT(s6a_parse_priority_level(hdr, &ptr->priority_level));
break;
case AVP_CODE_PRE_EMPTION_CAPABILITY:
CHECK_FCT(s6a_parse_pre_emp_capability(hdr, &ptr->pre_emp_capability));
break;
case AVP_CODE_PRE_EMPTION_VULNERABILITY:
CHECK_FCT(s6a_parse_pre_emp_vulnerability(hdr, &ptr->pre_emp_vulnerability));
break;
default:
return -1;
}
/* Go to next AVP in the grouped AVP */
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL));
}
return 0;
}
static inline
int s6a_parse_eps_subscribed_qos_profile(struct avp *avp_qos,
eps_subscribed_qos_profile_t *ptr)
{
struct avp *avp = NULL;
struct avp_hdr *hdr;
CHECK_FCT(fd_msg_browse(avp_qos, MSG_BRW_FIRST_CHILD, &avp, NULL));
while(avp) {
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
switch(hdr->avp_code) {
case AVP_CODE_QCI:
CHECK_FCT(s6a_parse_qci(hdr, &ptr->qci));
break;
case AVP_CODE_ALLOCATION_RETENTION_PRIORITY:
CHECK_FCT(s6a_parse_allocation_retention_priority(avp, &ptr->allocation_retention_priority));
break;
default:
return -1;
}
/* Go to next AVP in the grouped AVP */
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL));
}
return 0;
}
static inline
int s6a_parse_ip_address(struct avp_hdr *hdr, ip_address_t *ip_address)
{
uint16_t ip_type;
DevCheck(hdr->avp_value->os.len >= 2, hdr->avp_value->os.len, 2, 0);
ip_type = (hdr->avp_value->os.data[0] << 8) | (hdr->avp_value->os.data[1]);
if (ip_type == IANA_IPV4) {
/* This is an IPv4 address */
ip_address->pdn_type = IPv4;
DevCheck(hdr->avp_value->os.len == 6, hdr->avp_value->os.len, 6, ip_type);
memcpy(ip_address->address.ipv4_address, &hdr->avp_value->os.data[2], 4);
} else if (ip_type == IANA_IPV6) {
/* This is an IPv6 address */
ip_address->pdn_type = IPv6;
DevCheck(hdr->avp_value->os.len == 18, hdr->avp_value->os.len, 18, ip_type);
memcpy(ip_address->address.ipv6_address, &hdr->avp_value->os.data[2], 16);
} else {
/* unhandled case... */
return -1;
}
return 0;
}
static inline
int s6a_parse_apn_configuration(struct avp *avp_apn_conf_prof, apn_configuration_t *apn_config)
{
struct avp *avp = NULL;
struct avp_hdr *hdr;
CHECK_FCT(fd_msg_browse(avp_apn_conf_prof, MSG_BRW_FIRST_CHILD, &avp, NULL));
while(avp) {
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
switch(hdr->avp_code) {
case AVP_CODE_CONTEXT_IDENTIFIER:
apn_config->context_identifier = hdr->avp_value->u32;
break;
case AVP_CODE_SERVED_PARTY_IP_ADDRESS:
if (apn_config->nb_ip_address == 2) {
DevMessage("Only two IP addresses can be provided");
}
CHECK_FCT(s6a_parse_ip_address(hdr, &apn_config->ip_address[apn_config->nb_ip_address]));
apn_config->nb_ip_address++;
break;
case AVP_CODE_PDN_TYPE:
CHECK_FCT(s6a_parse_pdn_type(hdr, &apn_config->pdn_type));
break;
case AVP_CODE_SERVICE_SELECTION:
CHECK_FCT(s6a_parse_service_selection(hdr, apn_config->service_selection,
&apn_config->service_selection_length));
break;
case AVP_CODE_EPS_SUBSCRIBED_QOS_PROFILE:
CHECK_FCT(s6a_parse_eps_subscribed_qos_profile(avp, &apn_config->subscribed_qos));
break;
case AVP_CODE_AMBR:
CHECK_FCT(s6a_parse_ambr(avp, &apn_config->ambr));
break;
}
/* Go to next AVP in the grouped AVP */
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL));
}
return 0;
}
static inline
int s6a_parse_apn_configuration_profile(struct avp *avp_apn_conf_prof,
apn_config_profile_t *apn_config_profile)
{
struct avp *avp = NULL;
struct avp_hdr *hdr;
CHECK_FCT(fd_msg_browse(avp_apn_conf_prof, MSG_BRW_FIRST_CHILD, &avp, NULL));
while(avp) {
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
switch(hdr->avp_code) {
case AVP_CODE_CONTEXT_IDENTIFIER:
apn_config_profile->context_identifier = hdr->avp_value->u32;
break;
case AVP_CODE_ALL_APN_CONFIG_INC_IND:
CHECK_FCT(s6a_parse_all_apn_conf_inc_ind(hdr, &apn_config_profile->all_apn_conf_ind));
break;
case AVP_CODE_APN_CONFIGURATION: {
DevCheck(apn_config_profile->nb_apns < MAX_APN_PER_UE,
apn_config_profile->nb_apns, MAX_APN_PER_UE, 0);
CHECK_FCT(s6a_parse_apn_configuration(
avp, &apn_config_profile->apn_configuration[apn_config_profile->nb_apns]));
apn_config_profile->nb_apns++;
} break;
}
/* Go to next AVP in the grouped AVP */
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL));
}
return 0;
}
int s6a_parse_subscription_data(struct avp *avp_subscription_data,
subscription_data_t *subscription_data)
{
struct avp *avp = NULL;
struct avp_hdr *hdr;
CHECK_FCT(fd_msg_browse(avp_subscription_data, MSG_BRW_FIRST_CHILD, &avp, NULL));
while(avp) {
CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
switch(hdr->avp_code) {
case AVP_CODE_SUBSCRIBER_STATUS:
CHECK_FCT(s6a_parse_subscriber_status(hdr, &subscription_data->subscriber_status));
break;
case AVP_CODE_MSISDN:
CHECK_FCT(s6a_parse_msisdn(hdr, subscription_data->msisdn,
&subscription_data->msisdn_length));
break;
case AVP_CODE_NETWORK_ACCESS_MODE:
CHECK_FCT(s6a_parse_network_access_mode(hdr, &subscription_data->access_mode));
break;
case AVP_CODE_ACCESS_RESTRICTION_DATA:
CHECK_FCT(s6a_parse_access_restriction_data(hdr, &subscription_data->access_restriction));
break;
case AVP_CODE_AMBR:
CHECK_FCT(s6a_parse_ambr(avp, &subscription_data->subscribed_ambr));
break;
case AVP_CODE_APN_CONFIGURATION_PROFILE:
CHECK_FCT(s6a_parse_apn_configuration_profile(avp, &subscription_data->apn_config_profile));
break;
case AVP_CODE_SUBSCRIBED_PERIODIC_RAU_TAU_TIMER:
subscription_data->rau_tau_timer = hdr->avp_value->u32;
break;
default:
return -1;
}
/* Go to next AVP in the grouped AVP */
CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL));
}
return 0;
}