/******************************************************************************* 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 . 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 "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 * \date 2013 * \version 0.1 */ int s6a_add_subscription_data_avp(struct msg *message, mysql_ul_ans_t *mysql_ans) { int ret = -1, i = 0; mysql_pdn_t *pdns = NULL; uint8_t nb_pdns = 0; struct avp *avp = NULL, *child_avp = NULL; 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; }