strongswan/src/libcharon/plugins/osmo_epdg/osmo_epdg_db.c

165 lines
3.6 KiB
C

/*
* Copyright (C) 2023 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Alexander Couzens <acouzens@sysmocom.de>
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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.
*
*/
#include <daemon.h>
#include <plugins/plugin.h>
#include <collections/hashtable.h>
#include <threading/rwlock.h>
#include <unistd.h>
#include "osmo_epdg_plugin.h"
#include "osmo_epdg_db.h"
#include "osmo_epdg_utils.h"
typedef struct private_osmo_epdg_db_t private_osmo_epdg_db_t;
/**
* Private data of an osmo_epdg_db_t object.
*/
struct private_osmo_epdg_db_t {
/**
* Public osmo_epdg_db_t interface.
*/
osmo_epdg_db_t public;
/**
* subscriber hash by imsi (how to handle multiple?)
*/
hashtable_t *subscribers_imsi;
/**
* rwlock to lock access for changes
*/
rwlock_t *lock;
};
METHOD(osmo_epdg_db_t, create_subscriber, osmo_epdg_ue_t *,
private_osmo_epdg_db_t *this, ike_sa_t *ike_sa)
{
osmo_epdg_ue_t *ue;
char imsi[16] = {0};
uint32_t unique = ike_sa->get_unique_id(ike_sa);
if (get_imsi_ike(ike_sa, imsi, sizeof(imsi) - 1))
{
return NULL;
}
this->lock->write_lock(this->lock);
ue = this->subscribers_imsi->get(this->subscribers_imsi, imsi);
if (ue)
{
/* TODO: handle dups! */
this->lock->unlock(this->lock);
return ue;
}
ue = osmo_epdg_ue_create(unique, imsi);
if (!ue)
{
DBG1(DBG_NET, "epdg_db: failed to create UE!");
this->lock->unlock(this->lock);
return NULL;
}
this->subscribers_imsi->put(this->subscribers_imsi, ue->get_imsi(ue), ue);
ue->get(ue);
this->lock->unlock(this->lock);
return ue;
}
METHOD(osmo_epdg_db_t, get_subscriber, osmo_epdg_ue_t *,
private_osmo_epdg_db_t *this, char *imsi)
{
osmo_epdg_ue_t *ue;
this->lock->read_lock(this->lock);
ue = this->subscribers_imsi->get(this->subscribers_imsi, imsi);
if (ue)
{
ue->get(ue);
}
this->lock->unlock(this->lock);
return ue;
}
METHOD(osmo_epdg_db_t, get_subscriber_ike, osmo_epdg_ue_t *,
private_osmo_epdg_db_t *this, ike_sa_t *ike_sa)
{
char imsi[16] = {0};
if (get_imsi_ike(ike_sa, imsi, sizeof(imsi)))
{
return NULL;
}
return this->public.get_subscriber(&this->public, imsi);
}
METHOD(osmo_epdg_db_t, remove_subscriber, void,
private_osmo_epdg_db_t *this, const char *imsi)
{
osmo_epdg_ue_t *ue;
this->lock->write_lock(this->lock);
ue = this->subscribers_imsi->remove(this->subscribers_imsi, imsi);
this->lock->unlock(this->lock);
if (ue)
{
ue->put(ue);
}
}
CALLBACK(destroy_ue, void,
osmo_epdg_ue_t *ue, const void *key)
{
ue->put(ue);
}
METHOD(osmo_epdg_db_t, destroy, void,
private_osmo_epdg_db_t *this)
{
this->subscribers_imsi->destroy_function(this->subscribers_imsi, destroy_ue);
this->lock->destroy(this->lock);
free(this);
}
/**
* See header
*/
osmo_epdg_db_t *osmo_epdg_db_create()
{
private_osmo_epdg_db_t *this;
INIT(this,
.public = {
.create_subscriber = _create_subscriber,
.get_subscriber = _get_subscriber,
.get_subscriber_ike = _get_subscriber_ike,
.remove_subscriber = _remove_subscriber,
.destroy = _destroy,
},
.subscribers_imsi = hashtable_create(hashtable_hash_str, hashtable_equals_str, 128),
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
);
return &this->public;
}