277 lines
11 KiB
C
277 lines
11 KiB
C
/*******************************************************************************
|
|
|
|
Eurecom OpenAirInterface
|
|
Copyright(c) 1999 - 2013 Eurecom
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms and conditions of the GNU General Public License,
|
|
version 2, as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope 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, write to the Free Software Foundation, Inc.,
|
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
The full GNU General Public License is included in this distribution in
|
|
the file called "COPYING".
|
|
|
|
Contact Information
|
|
Openair Admin: openair_admin@eurecom.fr
|
|
Openair Tech : openair_tech@eurecom.fr
|
|
Forums : http://forums.eurecom.fr/openairinterface
|
|
Address : EURECOM, Campus SophiaTech, 450 Route des Chappes
|
|
06410 Biot FRANCE
|
|
|
|
*******************************************************************************/
|
|
|
|
#include "hss_config.h"
|
|
#include "db_proto.h"
|
|
#include "s6a_proto.h"
|
|
|
|
/*! \file s6a_subscription_data.c
|
|
* \brief Add the subscription data to a message. Data are retrieved from database
|
|
* \author Sebastien ROUX <sebastien.roux@eurecom.fr>
|
|
* \date 2013
|
|
* \version 0.1
|
|
*/
|
|
|
|
int s6a_add_subscription_data_avp(struct msg *message, mysql_ul_ans_t *mysql_ans)
|
|
{
|
|
int ret = -1, i;
|
|
mysql_pdn_t *pdns;
|
|
uint8_t nb_pdns;
|
|
struct avp *avp, *child_avp;
|
|
union avp_value value;
|
|
|
|
if (mysql_ans == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
ret = hss_mysql_query_pdns(mysql_ans->imsi, &pdns, &nb_pdns);
|
|
|
|
if (ret != 0) {
|
|
/* mysql query failed:
|
|
* - maybe no more memory
|
|
* - maybe user is not known (should have failed before)
|
|
* - maybe imsi has no EPS subscribed
|
|
*/
|
|
goto out;
|
|
}
|
|
|
|
if (nb_pdns == 0)
|
|
{
|
|
/* No PDN for this user -> DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION */
|
|
return -1;
|
|
}
|
|
|
|
/* Create the Subscription-Data AVP */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_subscription_data, 0, &avp));
|
|
|
|
{
|
|
uint8_t msisdn_len = strlen(mysql_ans->msisdn);
|
|
/* The MSISDN is known in the HSS, add it to the subscription data */
|
|
if (msisdn_len > 0) {
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_msisdn, 0, &child_avp));
|
|
value.os.data = (uint8_t *)mysql_ans->msisdn;
|
|
value.os.len = msisdn_len;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
}
|
|
}
|
|
|
|
/* We have to include the acess-restriction-data if the value stored in DB
|
|
* indicates that at least one restriction is applied to the USER.
|
|
*/
|
|
if (mysql_ans->access_restriction != 0) {
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_access_restriction_data, 0, &child_avp));
|
|
value.u32 = (uint32_t)mysql_ans->access_restriction;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
}
|
|
|
|
/* Add the Subscriber-Status to the list of AVP.
|
|
* It shall indicate if the service is barred or granted.
|
|
* TODO: normally this parameter comes from DB...
|
|
*/
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_subscriber_status, 0, &child_avp));
|
|
/* SERVICE_GRANTED */
|
|
value.u32 = 0;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Add the Network-Access-Mode to the list of AVP.
|
|
* LTE Standalone HSS/MME: ONLY_PACKET.
|
|
*/
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_network_access_mode, 0, &child_avp));
|
|
/* SERVICE_GRANTED */
|
|
value.u32 = 2;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Add the AMBR to list of AVPs */
|
|
{
|
|
struct avp *bandwidth;
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_ambr, 0, &child_avp));
|
|
|
|
/* Uplink bandwidth */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_ul, 0, &bandwidth));
|
|
value.u32 = mysql_ans->aggr_ul;
|
|
CHECK_FCT(fd_msg_avp_setvalue(bandwidth, &value));
|
|
CHECK_FCT(fd_msg_avp_add(child_avp, MSG_BRW_LAST_CHILD, bandwidth));
|
|
|
|
/* Downlink bandwidth */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_dl, 0, &bandwidth));
|
|
value.u32 = mysql_ans->aggr_dl;
|
|
CHECK_FCT(fd_msg_avp_setvalue(bandwidth, &value));
|
|
CHECK_FCT(fd_msg_avp_add(child_avp, MSG_BRW_LAST_CHILD, bandwidth));
|
|
|
|
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
}
|
|
|
|
/* Add the APN-Configuration-Profile only if at least one APN is subscribed */
|
|
if (nb_pdns > 0)
|
|
{
|
|
struct avp *apn_profile;
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_apn_configuration_profile,
|
|
0, &apn_profile));
|
|
|
|
/* Context-Identifier */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_context_identifier, 0, &child_avp));
|
|
value.u32 = 0;
|
|
/* TODO: this is the reference to the default APN... */
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(apn_profile, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* All-APN-Configurations-Included-Indicator */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_all_apn_conf_inc_ind, 0, &child_avp));
|
|
value.u32 = 0;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(apn_profile, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
for (i = 0; i < nb_pdns; i++)
|
|
{
|
|
struct avp *apn_configuration;
|
|
mysql_pdn_t *pdn_elm;
|
|
|
|
pdn_elm = &pdns[i];
|
|
|
|
/* APN-Configuration */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_apn_configuration, 0, &apn_configuration));
|
|
|
|
/* Context-Identifier */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_context_identifier, 0, &child_avp));
|
|
value.u32 = i;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* PDN-Type */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_pdn_type, 0, &child_avp));
|
|
value.u32 = pdn_elm->pdn_type;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
if ((pdn_elm->pdn_type == IPV4) ||
|
|
(pdn_elm->pdn_type == IPV4_OR_IPV6) ||
|
|
(pdn_elm->pdn_type == IPV4V6))
|
|
{
|
|
s6a_add_ipv4_address(apn_configuration, pdn_elm->pdn_address.ipv4_address);
|
|
}
|
|
if ((pdn_elm->pdn_type == IPV6) ||
|
|
(pdn_elm->pdn_type == IPV4_OR_IPV6) ||
|
|
(pdn_elm->pdn_type == IPV4V6))
|
|
{
|
|
s6a_add_ipv6_address(apn_configuration, pdn_elm->pdn_address.ipv6_address);
|
|
}
|
|
|
|
/* Service-Selection */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_service_selection, 0, &child_avp));
|
|
value.os.data = (uint8_t*)pdn_elm->apn;
|
|
value.os.len = strlen(pdn_elm->apn);
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Add the eps subscribed qos profile */
|
|
{
|
|
struct avp *qos_profile, *allocation_priority;
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_eps_subscribed_qos_profile, 0, &qos_profile));
|
|
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_qos_class_identifier, 0, &child_avp));
|
|
/* For a QCI_1 */
|
|
value.u32 = (uint32_t)pdn_elm->qci;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(qos_profile, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Allocation retention priority */
|
|
{
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_allocation_retention_priority, 0, &allocation_priority));
|
|
|
|
/* Priority level */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_priority_level, 0, &child_avp));
|
|
value.u32 = (uint32_t)pdn_elm->priority_level;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(allocation_priority, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Pre-emption-capability */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_pre_emption_capability, 0, &child_avp));
|
|
value.u32 = (uint32_t)pdn_elm->pre_emp_cap;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(allocation_priority, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Pre-emption-vulnerability */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_pre_emption_vulnerability, 0, &child_avp));
|
|
value.u32 = (uint32_t)pdn_elm->pre_emp_vul;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(allocation_priority, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
CHECK_FCT(fd_msg_avp_add(qos_profile, MSG_BRW_LAST_CHILD, allocation_priority));
|
|
}
|
|
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, qos_profile));
|
|
}
|
|
|
|
/* Add the AMBR to list of AVPs */
|
|
{
|
|
struct avp *bandwidth;
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_ambr, 0, &bandwidth));
|
|
|
|
/* Uplink bandwidth */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_ul, 0, &child_avp));
|
|
value.u32 = (uint32_t)pdn_elm->aggr_ul;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(bandwidth, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Downlink bandwidth */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_max_bandwidth_dl, 0, &child_avp));
|
|
value.u32 = (uint32_t)pdn_elm->aggr_dl;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(bandwidth, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
CHECK_FCT(fd_msg_avp_add(apn_configuration, MSG_BRW_LAST_CHILD, bandwidth));
|
|
}
|
|
|
|
CHECK_FCT(fd_msg_avp_add(apn_profile, MSG_BRW_LAST_CHILD, apn_configuration));
|
|
}
|
|
|
|
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, apn_profile));
|
|
}
|
|
|
|
/* Subscribed-Periodic-RAU-TAU-Timer */
|
|
CHECK_FCT(fd_msg_avp_new(s6a_cnf.dataobj_s6a_subscribed_rau_tau_timer, 0, &child_avp));
|
|
/* Request an RAU/TAU update every x seconds */
|
|
value.u32 = (uint32_t)mysql_ans->rau_tau;
|
|
CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value));
|
|
CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp));
|
|
|
|
/* Add the AVP to the message */
|
|
CHECK_FCT(fd_msg_avp_add(message, MSG_BRW_LAST_CHILD, avp));
|
|
|
|
out:
|
|
if (pdns) {
|
|
free(pdns);
|
|
}
|
|
return ret;
|
|
}
|