/*
 * (C) 2021-2022 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 <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 up_peer_event {
	UP_PEER_EV_RX_ASSOC_SETUP_REQ,
	UP_PEER_EV_RX_ASSOC_UPD_REQ,
	UP_PEER_EV_RX_ASSOC_REL_REQ,
	UP_PEER_EV_RX_SESSION_EST_REQ,
	UP_PEER_EV_HEARTBEAT_FAILURE,
	UP_PEER_EV_USE_COUNT_ZERO,
	UP_PEER_EV_SESSION_TERM,
};

struct up_peer {
	/* item in up_endpoint->peers */
	struct llist_head entry;

	struct osmo_fsm_inst *fi;
	/* backpointer */
	struct up_endpoint *up_endpoint;

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

	struct osmo_pfcp_ie_up_function_features local_up_features;
	struct osmo_pfcp_ie_cp_function_features peer_cp_features;

	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 up_peer *up_peer_find_or_add(struct up_endpoint *up_ep, const struct osmo_sockaddr *remote_addr);
struct up_peer *up_peer_find(struct up_endpoint *up_ep, const struct osmo_sockaddr *remote_addr);

void up_peer_set_msg_ctx(struct up_peer *peer, struct osmo_pfcp_msg *m);

char *up_peer_remote_addr_str(struct up_peer *peer);

struct osmo_pfcp_msg *up_peer_init_tx(struct up_peer *peer, struct osmo_pfcp_msg *in_reply_to,
				      enum osmo_pfcp_message_type message_type);

void up_peer_free(struct up_peer *peer);
