Files
openairinterface5g/openair-cn/OPENAIRHSS/db/db_connector.c
T

586 lines
17 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 <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <error.h>
#include <inttypes.h>
#include <mysql/mysql.h>
#include "hss_config.h"
#include "db_proto.h"
database_t *db_desc;
static void print_buffer(const char *prefix, uint8_t *buffer, int length)
{
int i;
fprintf(stdout, "%s", prefix);
for (i = 0; i < length; i++) {
fprintf(stdout, "%02x.", buffer[i]);
}
fprintf(stdout, "\n");
}
int hss_mysql_connect(const hss_config_t *hss_config_p)
{
const int mysql_reconnect_val = 1;
if ((hss_config_p->mysql_server == NULL) ||
(hss_config_p->mysql_user == NULL) ||
(hss_config_p->mysql_password == NULL) ||
(hss_config_p->mysql_database == NULL))
{
DB_ERROR("An empty name is not allowed\n");
return EINVAL;
}
DB_DEBUG("Initializing db layer\n");
db_desc = malloc(sizeof(database_t));
if (db_desc == NULL) {
DB_DEBUG("An error occured on MALLOC\n");
return errno;
}
pthread_mutex_init(&db_desc->db_cs_mutex, NULL);
/* Copy database configuration from static hss config */
db_desc->server = strdup(hss_config_p->mysql_server);
db_desc->user = strdup(hss_config_p->mysql_user);
db_desc->password = strdup(hss_config_p->mysql_password);
db_desc->database = strdup(hss_config_p->mysql_database);
/* Init mySQL client */
db_desc->db_conn = mysql_init(NULL);
mysql_options(db_desc->db_conn, MYSQL_OPT_RECONNECT, &mysql_reconnect_val);
/* Try to connect to database */
if (!mysql_real_connect(db_desc->db_conn, db_desc->server, db_desc->user,
db_desc->password, db_desc->database, 0, NULL, 0)) {
DB_ERROR("An error occured while connecting to db: %s\n",
mysql_error(db_desc->db_conn));
return -1;
}
/* Set the multi statement ON */
mysql_set_server_option(db_desc->db_conn, MYSQL_OPTION_MULTI_STATEMENTS_ON);
DB_DEBUG("Initializing db layer: DONE\n");
return 0;
}
void hss_mysql_disconnect(void)
{
mysql_close(db_desc->db_conn);
}
int hss_mysql_update_loc(const char *imsi, mysql_ul_ans_t *mysql_ul_ans)
{
MYSQL_RES *res;
MYSQL_ROW row;
char query[255];
int ret = 0;
if ((db_desc->db_conn == NULL) || (mysql_ul_ans == NULL)) {
return EINVAL;
}
if (strlen(imsi) > 15) {
return EINVAL;
}
sprintf(query, "SELECT `access_restriction`,`mmeidentity_idmmeidentity`,"
"`msisdn`,`ue_ambr_ul`,`ue_ambr_dl`,`rau_tau_timer` "
"FROM `users` WHERE `users`.`imsi`='%s' ", imsi);
memcpy(mysql_ul_ans->imsi, imsi, strlen(imsi) + 1);
DB_DEBUG("Query: %s\n", query);
pthread_mutex_lock(&db_desc->db_cs_mutex);
if (mysql_query(db_desc->db_conn, query))
{
pthread_mutex_unlock(&db_desc->db_cs_mutex);
DB_ERROR("Query execution failed: %s\n",
mysql_error(db_desc->db_conn));
mysql_thread_end();
return EINVAL;
}
res = mysql_store_result(db_desc->db_conn);
pthread_mutex_unlock(&db_desc->db_cs_mutex);
if ((row = mysql_fetch_row(res)) != NULL) {
int mme_id;
/* MSISDN may be NULL */
mysql_ul_ans->access_restriction = atoi(row[0]);
if ((mme_id = atoi(row[1])) > 0) {
ret = hss_mysql_query_mmeidentity(mme_id, &mysql_ul_ans->mme_identity);
} else {
mysql_ul_ans->mme_identity.mme_host[0] = '\0';
mysql_ul_ans->mme_identity.mme_realm[0] = '\0';
}
if (row[2] != 0) {
memcpy(mysql_ul_ans->msisdn, row[2], strlen(row[2]));
}
mysql_ul_ans->aggr_ul = atoi(row[3]);
mysql_ul_ans->aggr_dl = atoi(row[4]);
mysql_ul_ans->rau_tau = atoi(row[5]);
mysql_free_result(res);
mysql_thread_end();
return ret;
}
mysql_free_result(res);
mysql_thread_end();
return EINVAL;
}
int hss_mysql_purge_ue(mysql_pu_req_t *mysql_pu_req,
mysql_pu_ans_t *mysql_pu_ans)
{
MYSQL_RES *res;
MYSQL_ROW row;
char query[255];
int ret = 0;
if ((db_desc->db_conn == NULL) ||
(mysql_pu_req == NULL) ||
(mysql_pu_ans == NULL))
{
return EINVAL;
}
if (strlen(mysql_pu_req->imsi) > 15) {
return EINVAL;
}
sprintf(query, "UPDATE `users` SET `users`.`ms_ps_status`=\"PURGED\" "
"WHERE `users`.`imsi`='%s'; "
"SELECT `users`.`mmeidentity_idmmeidentity` FROM `users` "
"WHERE `users`.`imsi`=%s ",
mysql_pu_req->imsi, mysql_pu_req->imsi);
DB_DEBUG("Query: %s\n", query);
pthread_mutex_lock(&db_desc->db_cs_mutex);
if (mysql_query(db_desc->db_conn, query))
{
pthread_mutex_unlock(&db_desc->db_cs_mutex);
DB_ERROR("Query execution failed: %s\n",
mysql_error(db_desc->db_conn));
mysql_thread_end();
return EINVAL;
}
res = mysql_store_result(db_desc->db_conn);
pthread_mutex_unlock(&db_desc->db_cs_mutex);
if ((row = mysql_fetch_row(res)) != NULL) {
int mme_id;
if ((mme_id = atoi(row[0])) > 0) {
ret = hss_mysql_query_mmeidentity(mme_id, mysql_pu_ans);
} else {
mysql_pu_ans->mme_host[0] = '\0';
mysql_pu_ans->mme_realm[0] = '\0';
}
mysql_free_result(res);
mysql_thread_end();
return ret;
}
mysql_free_result(res);
mysql_thread_end();
return EINVAL;
}
int hss_mysql_get_user(const char *imsi)
{
MYSQL_RES *res;
MYSQL_ROW row;
char query[255];
if (db_desc->db_conn == NULL) {
return EINVAL;
}
sprintf(query, "SELECT `imsi` FROM `users` WHERE `users`.`imsi`=%s ", imsi);
DB_DEBUG("Query: %s\n", query);
pthread_mutex_lock(&db_desc->db_cs_mutex);
if (mysql_query(db_desc->db_conn, query))
{
pthread_mutex_unlock(&db_desc->db_cs_mutex);
DB_ERROR("Query execution failed: %s\n",
mysql_error(db_desc->db_conn));
mysql_thread_end();
return EINVAL;
}
res = mysql_store_result(db_desc->db_conn);
pthread_mutex_unlock(&db_desc->db_cs_mutex);
if ((row = mysql_fetch_row(res)) != NULL) {
mysql_free_result(res);
mysql_thread_end();
return 0;
}
mysql_free_result(res);
mysql_thread_end();
return EINVAL;
}
int mysql_push_up_loc(mysql_ul_push_t *ul_push_p)
{
MYSQL_RES *res;
char query[500];
int query_length = 0;
int status;
if ((db_desc->db_conn == NULL) || (ul_push_p == NULL)) {
return EINVAL;
}
// TODO: multi-statement check results
if (ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT) {
query_length += sprintf(&query[query_length], "INSERT INTO `mmeidentity`"
" (`mmehost`,`mmerealm`) SELECT '%s','%s' FROM `mmeidentity` WHERE NOT"
" EXISTS (SELECT * FROM `mmeidentity` WHERE `mmehost`='%s'"
" AND `mmerealm`='%s') LIMIT 1;", ul_push_p->mme_identity.mme_host,
ul_push_p->mme_identity.mme_realm, ul_push_p->mme_identity.mme_host,
ul_push_p->mme_identity.mme_realm);
}
query_length += sprintf(&query[query_length], "UPDATE `users`%s SET ",
ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT ?
",`mmeidentity`" : "");
if (ul_push_p->imei_present == IMEI_PRESENT) {
query_length += sprintf(&query[query_length], "`imei`='%s',",
ul_push_p->imei);
}
if (ul_push_p->sv_present == SV_PRESENT) {
query_length += sprintf(&query[query_length], "`imeisv`='%*s',", 2,
ul_push_p->software_version);
}
if (ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT) {
query_length += sprintf(&query[query_length],
"`users`.`mmeidentity_idmmeidentity`=`mmeidentity`.`idmmeidentity`, "
"`users`.`ms_ps_status`=\"NOT_PURGED\"");
}
query_length += sprintf(&query[query_length], " WHERE `users`.`imsi`='%s'",
ul_push_p->imsi);
if (ul_push_p->mme_identity_present == MME_IDENTITY_PRESENT) {
query_length += sprintf(&query[query_length],
" AND `mmeidentity`.`mmehost`='%s'"
" AND `mmeidentity`.`mmerealm`='%s'",
ul_push_p->mme_identity.mme_host, ul_push_p->mme_identity.mme_realm);
}
DB_DEBUG("Query: %s\n", query);
pthread_mutex_lock(&db_desc->db_cs_mutex);
if (mysql_query(db_desc->db_conn, query))
{
pthread_mutex_unlock(&db_desc->db_cs_mutex);
fprintf(stderr, "Query execution failed: %s\n",
mysql_error(db_desc->db_conn));
mysql_thread_end();
return EINVAL;
}
/* process each statement result */
do {
/* did current statement return data? */
res = mysql_store_result(db_desc->db_conn);
if (res)
{
/* yes; process rows and free the result set */
mysql_free_result(res);
}
else /* no result set or error */
{
if (mysql_field_count(db_desc->db_conn) == 0)
{
DB_ERROR("%lld rows affected\n",
mysql_affected_rows(db_desc->db_conn));
}
else /* some error occurred */
{
DB_ERROR("Could not retrieve result set\n");
break;
}
}
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
if ((status = mysql_next_result(db_desc->db_conn)) > 0)
DB_ERROR("Could not execute statement\n");
} while (status == 0);
pthread_mutex_unlock(&db_desc->db_cs_mutex);
mysql_free_result(res);
mysql_thread_end();
return 0;
}
int hss_mysql_push_rand_sqn(const char *imsi, uint8_t *rand_p, uint8_t *sqn)
{
int status = 0, i;
MYSQL_RES *res;
MYSQL_ROW row;
char query[255];
int query_length = 0;
uint64_t sqn_decimal = 0;
if (db_desc->db_conn == NULL) {
return EINVAL;
}
if (rand_p == NULL || sqn == NULL) {
return EINVAL;
}
sqn_decimal = ((uint64_t)sqn[0] << 40) | ((uint64_t)sqn[1] << 32) |
(sqn[2] << 24) | (sqn[3] << 16) | (sqn[4] << 8) | sqn[5];
query_length = sprintf(query, "UPDATE `users` SET `rand`=UNHEX('");
for (i = 0; i < RAND_LENGTH; i ++) {
query_length += sprintf(&query[query_length], "%02x", rand_p[i]);
}
query_length += sprintf(&query[query_length], "'),`sqn`=%"PRIu64, sqn_decimal);
query_length += sprintf(&query[query_length], " WHERE `users`.`imsi`='%s'", imsi);
DB_DEBUG("Query: %s\n", query);
pthread_mutex_lock(&db_desc->db_cs_mutex);
if (mysql_query(db_desc->db_conn, query))
{
pthread_mutex_unlock(&db_desc->db_cs_mutex);
DB_ERROR("Query execution failed: %s\n",
mysql_error(db_desc->db_conn));
mysql_thread_end();
return EINVAL;
}
/* process each statement result */
do {
/* did current statement return data? */
res = mysql_store_result(db_desc->db_conn);
if (res)
{
/* yes; process rows and free the result set */
mysql_free_result(res);
}
else /* no result set or error */
{
if (mysql_field_count(db_desc->db_conn) == 0)
{
DB_ERROR("%lld rows affected\n",
mysql_affected_rows(db_desc->db_conn));
}
else /* some error occurred */
{
DB_ERROR("Could not retrieve result set\n");
break;
}
}
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
if ((status = mysql_next_result(db_desc->db_conn)) > 0)
DB_ERROR("Could not execute statement\n");
} while (status == 0);
pthread_mutex_unlock(&db_desc->db_cs_mutex);
mysql_free_result(res);
mysql_thread_end();
return 0;
}
int hss_mysql_increment_sqn(const char *imsi)
{
int status;
MYSQL_RES *res;
char query[255];
if (db_desc->db_conn == NULL) {
return EINVAL;
}
if (imsi == NULL) {
return EINVAL;
}
/* + 32 = 2 ^ sizeof(IND) (see 3GPP TS. 33.102) */
sprintf(query, "UPDATE `users` SET `sqn` = `sqn` + 32 WHERE `users`.`imsi`=%s", imsi);
DB_DEBUG("Query: %s\n", query);
if (mysql_query(db_desc->db_conn, query))
{
pthread_mutex_unlock(&db_desc->db_cs_mutex);
DB_ERROR("Query execution failed: %s\n",
mysql_error(db_desc->db_conn));
mysql_thread_end();
return EINVAL;
}
/* process each statement result */
do {
/* did current statement return data? */
res = mysql_store_result(db_desc->db_conn);
if (res)
{
/* yes; process rows and free the result set */
mysql_free_result(res);
}
else /* no result set or error */
{
if (mysql_field_count(db_desc->db_conn) == 0)
{
DB_ERROR("%lld rows affected\n",
mysql_affected_rows(db_desc->db_conn));
}
else /* some error occurred */
{
DB_ERROR("Could not retrieve result set\n");
break;
}
}
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
if ((status = mysql_next_result(db_desc->db_conn)) > 0)
DB_ERROR("Could not execute statement\n");
} while (status == 0);
pthread_mutex_unlock(&db_desc->db_cs_mutex);
mysql_free_result(res);
mysql_thread_end();
return 0;
}
int hss_mysql_auth_info(mysql_auth_info_req_t *auth_info_req,
mysql_auth_info_resp_t *auth_info_resp)
{
int ret = 0;
MYSQL_RES *res;
MYSQL_ROW row;
char query[255];
if (db_desc->db_conn == NULL) {
return EINVAL;
}
if ((auth_info_req == NULL) || (auth_info_resp == NULL)) {
return EINVAL;
}
sprintf(query, "SELECT `key`,`sqn`,`rand` FROM `users` WHERE `users`.`imsi`=%s ",
auth_info_req->imsi);
DB_DEBUG("Query: %s\n", query);
pthread_mutex_lock(&db_desc->db_cs_mutex);
if (mysql_query(db_desc->db_conn, query))
{
pthread_mutex_unlock(&db_desc->db_cs_mutex);
DB_ERROR("Query execution failed: %s\n",
mysql_error(db_desc->db_conn));
mysql_thread_end();
return EINVAL;
}
res = mysql_store_result(db_desc->db_conn);
pthread_mutex_unlock(&db_desc->db_cs_mutex);
if ((row = mysql_fetch_row(res)) != NULL) {
if (row[0] == NULL || row[1] == NULL || row[2] == NULL) {
ret = EINVAL;
}
if (row[0] != NULL) {
print_buffer("Key: ", (uint8_t*)row[0], KEY_LENGTH);
memcpy(auth_info_resp->key, row[0], KEY_LENGTH);
}
if (row[1] != NULL) {
uint64_t sqn = 0;
sqn = atoll(row[1]);
printf("Received SQN %s converted to %"PRIu64"\n", row[1], sqn);
auth_info_resp->sqn[0] = (sqn & (255UL << 40)) >> 40;
auth_info_resp->sqn[1] = (sqn & (255UL << 32)) >> 32;
auth_info_resp->sqn[2] = (sqn & (255UL << 24)) >> 24;
auth_info_resp->sqn[3] = (sqn & (255UL << 16)) >> 16;
auth_info_resp->sqn[4] = (sqn & (255UL << 8)) >> 8;
auth_info_resp->sqn[5] = (sqn & 0xFF);
print_buffer("SQN: ", auth_info_resp->sqn, SQN_LENGTH);
}
if (row[2] != NULL) {
print_buffer("RAND: ", (uint8_t*)row[2], RAND_LENGTH);
memcpy(auth_info_resp->rand, row[2], RAND_LENGTH);
}
mysql_free_result(res);
mysql_thread_end();
return ret;
}
mysql_free_result(res);
mysql_thread_end();
return EINVAL;
}