#pragma once
/* q931.c - Q.931 protocol definitions
 *
 * (C) 2022 by Harald Welte <laforge@osmocom.org>
 *
 * All Rights Reserved
 *
 * 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 <stdint.h>
#include <stdbool.h>
#include <osmocom/gsm/tlv.h>

/* Table 4-2/Q.931 - Message types */
enum q931_msg_type {
	/* Call establishment messages */
	Q931_MSGT_ALERTING		= 0x01,
	Q931_MSGT_CALL_PROCEEDING	= 0x02,
	Q931_MSGT_CONNECT		= 0x07,
	Q931_MSGT_CONNECT_ACK		= 0x0f,
	Q931_MSGT_PROGRESS		= 0x03,
	Q931_MSGT_SETUP			= 0x05,
	Q931_MSGT_SETUP_ACK		= 0x0d,
	/* Call information phase messages */
	Q931_MSGT_RESUME		= 0x26,
	Q931_MSGT_RESUME_ACK		= 0x2e,
	Q931_MSGT_RESUME_REJ		= 0x22,
	Q931_MSGT_SUSPEND		= 0x25,
	Q931_MSGT_SUSPEND_ACK		= 0x2d,
	Q931_MSGT_SUSPEND_REJ		= 0x21,
	Q931_MSGT_USER_INFO		= 0x20,
	/* Call clearing messages */
	Q931_MSGT_DISCONNECT		= 0x45,
	Q931_MSGT_RELEASE		= 0x4d,
	Q931_MSGT_RELEASE_COMPLETE	= 0x5a,
	Q931_MSGT_RESTART		= 0x46,
	Q931_MSGT_RESTART_ACK		= 0x4e,
	/* Miscellaneous messages */
	Q931_MSGT_SEGMENT		= 0x60,
	Q931_MSGT_CONGESTION_CTRL	= 0x79,
	Q931_MSGT_INFORMATION		= 0x7b,
	Q931_MSGT_NOTIFY		= 0x6e,
	Q931_MSGT_STATUS		= 0x7d,
	Q931_MSGT_STATUS_ENQIURY	= 0x75,
};

extern const struct value_string q931_msg_type_vals[];

/* Table 4-3/Q.931 */
enum q931_iei {
	/* reserved */
	/* shift */
	Q931_IEI_MORE_DATA		= 0xa0,
	Q931_IEI_SENDING_COMPLETE	= 0xa1,
	/* contentionlevel */
	/* repeat indicator */
	/* Veriable length IEs */
	Q931_IEI_SEGMENTED_MSG		= 0x00,
	Q931_IEI_BEARER_CAP		= 0x04,
	Q931_IEI_CAUSE			= 0x08,
	Q931_IEI_CALL_ID		= 0x10,
	Q931_IEI_CALL_STATE		= 0x14,
	Q931_IEI_CHANNEL_ID		= 0x18,
	Q931_IEI_PROGRESS_IND		= 0x1e,
	Q931_IEI_NETWORK_SPEC_FAC	= 0x20,
	Q931_IEI_NOTIFICATION_IND	= 0x27,
	Q931_IEI_DISPLAY		= 0x28,
	Q931_IEI_DATE_TIME		= 0x29,
	Q931_IEI_KEYPAD_FACILITY	= 0x2c,
	Q931_IEI_SIGNAL			= 0x34,
	Q931_IEI_INFORMATION_RATE	= 0x40,
	Q931_IEI_E2E_TRANSIT_DELAY	= 0x42,
	Q931_IEI_TRANSIT_DELAY_SEL_AND_IND = 0x43,
	Q931_IEI_PKT_LAYER_BIN_PARAMS	= 0x44,
	Q931_IEI_PKT_LAYER_WIN_SIZE	= 0x45,
	Q931_IEI_PACKET_SIZE		= 0x46,
	Q931_IEI_CLOSED_USER_GROUP	= 0x47,
	Q931_IEI_REV_CHARGING_IND	= 0x4a,
	Q931_IEI_CALLING_PARTY_NUM	= 0x6c,
	Q931_IEI_CALLING_PARTY_SUBADDR	= 0x6d,
	Q931_IEI_CALLED_PARTY_NUM	= 0x70,
	Q931_IEI_CALLED_PARTY_SUBADDR	= 0x71,
	Q931_IEI_TRANSIT_NET_SEL	= 0x78,
	Q931_IEI_RESTART_IND		= 0x79,
	Q931_IEI_LOW_LAYER_COMPAT	= 0x7c,
	Q931_IEI_HIGH_LAYER_COMPAT	= 0x7d,
	Q931_IEI_ESCAPE_FOR_EXT		= 0x7f,
};

struct q931_msg_parsed {
	uint8_t msg_type;
	uint32_t call_ref;
	struct tlv_parsed ies;
};

int q931_msg_parse(struct q931_msg_parsed *out, const uint8_t *buf, size_t len);

uint32_t q931_decode_callref(const uint8_t *data, uint8_t len);

/* Q.931 Section 4.5.13 */
enum q931_info_chan_type {
	Q931_INFO_CHAN_T_NONE,
	Q931_INFO_CHAN_T_ANY,
	Q931_INFO_CHAN_T_SPECIFIC,
};

/* decoded version of (simplified) Q.931 Channel Identification IE */
struct q931_channel_id {
	bool interface_id_present;
	uint32_t interface_id;
	bool interface_type_pri;
	bool exclusive;
	bool d_channel;
	enum q931_info_chan_type info_chan_type;
	uint32_t b_channel;	/* 1..2 on BRI; 1..31 on PRI */
};


int q931_decode_channel_id(struct q931_channel_id *out, const uint8_t *data, uint8_t len);

struct q931_party_number {
	uint8_t type_of_number;
	uint8_t numbering_plan_id;
	uint8_t presentation_ind;
	uint8_t screening_ind;
	char digits[32];
};

int q931_decode_called_party(struct q931_party_number *out, const uint8_t *buf, size_t len);
int q931_decode_calling_party(struct q931_party_number *out, const uint8_t *buf, size_t len);
