/* 3GPP TS 29.244 PFCP Entity
 * (C) 2021-2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 * All Rights Reserved.
 *
 * Author: Neels Janosch Hofmeyr <nhofmeyr@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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#pragma once

#include <stdint.h>

#include <osmocom/core/linuxlist.h>
#include <osmocom/core/hashtable.h>
#include <osmocom/core/socket.h>
#include <osmocom/core/use_count.h>

#include <osmocom/pfcp/pfcp_msg.h>

enum pfcp_entity_peer_event {
	PFCP_ENTITY_PEER_EV_RX_ASSOC_SETUP_REQ,
	PFCP_ENTITY_PEER_EV_RX_ASSOC_UPD_REQ,
	PFCP_ENTITY_PEER_EV_RX_ASSOC_REL_REQ,
	PFCP_ENTITY_PEER_EV_RX_SESSION_EST_REQ,
	PFCP_ENTITY_PEER_EV_HEARTBEAT_FAILURE,
	PFCP_ENTITY_PEER_EV_USE_COUNT_ZERO,
	PFCP_ENTITY_PEER_EV_SESSION_TERM,
};

struct pfcp_entity_peer {
	/* item in pfcp_node_peer->entity_list */
	struct llist_head entry;

	struct osmo_fsm_inst *fi;
	/* backpointer */
	struct pfcp_node_peer *node_peer;

	/* peer's remote address */
	struct osmo_sockaddr remote_addr;
	uint32_t remote_recovery_timestamp;

	uint32_t next_seq_nr;

	struct osmo_fsm_inst *heartbeat_fi;

	struct osmo_use_count use_count;
	struct osmo_use_count_entry use_count_buf[5];

	DECLARE_HASHTABLE(sessions_by_up_seid, 10);
	DECLARE_HASHTABLE(sessions_by_cp_seid, 10);
};

struct pfcp_entity_peer *pfcp_entity_peer_alloc(struct pfcp_node_peer *node_peer, const struct osmo_sockaddr *remote_addr);
void pfcp_entity_peer_free(struct pfcp_entity_peer *peer);

void pfcp_entity_peer_set_msg_ctx(struct pfcp_entity_peer *entity_peer, struct osmo_pfcp_msg *m);
void pfcp_entity_peer_remove_msg_ctx(struct pfcp_entity_peer *peer, struct osmo_pfcp_msg *m);

char *pfcp_entity_peer_remote_addr_str(struct pfcp_entity_peer *entity_peer);

struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_req(struct pfcp_entity_peer *peer,
						   const struct osmo_sockaddr *dst_addr,
						   enum osmo_pfcp_message_type message_type);
struct osmo_pfcp_msg *pfcp_entity_peer_init_tx_resp(struct pfcp_entity_peer *peer,
						    struct osmo_pfcp_msg *in_reply_to,
						    enum osmo_pfcp_message_type message_type);

struct up_session *pfcp_entity_peer_find_up_session_by_up_seid(struct pfcp_entity_peer *entity_peer, uint64_t up_seid);
struct up_session *pfcp_entity_peer_find_up_session_by_cp_f_seid(struct pfcp_entity_peer *entity_peer, const struct osmo_pfcp_ie_f_seid *cp_f_seid);

