changeset 1:b161dbfffdaa

include, libutil: port from old ThemWi
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 08 Jun 2024 23:06:53 +0000
parents 214716b13c61
children 053f04687106
files include/gsm48_const.h include/mncc.h libutil/Makefile libutil/dtmf_valid.c libutil/extdigits.c libutil/imsi_entry.c libutil/mncc_debug.c libutil/mncc_utils.c libutil/sockinit.c
diffstat 9 files changed, 805 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/gsm48_const.h	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,163 @@
+/*
+ * This header file contains some GSM 04.08 constants pulled from
+ * Osmocom header file <osmocom/gsm/protocol/gsm_04_08.h>,
+ * beyond those included in mncc.h essential interface definition.
+ */
+
+#ifndef	__GSM48_CONST_H
+#define	__GSM48_CONST_H
+
+enum gsm48_chan_mode {
+	GSM48_CMODE_SIGN	= 0x00,
+	GSM48_CMODE_SPEECH_V1	= 0x01,
+	GSM48_CMODE_SPEECH_EFR	= 0x21,
+	GSM48_CMODE_SPEECH_AMR	= 0x41,
+	GSM48_CMODE_DATA_14k5	= 0x0f,
+	GSM48_CMODE_DATA_12k0	= 0x03,
+	GSM48_CMODE_DATA_6k0	= 0x0b,
+	GSM48_CMODE_DATA_3k6	= 0x13,
+	GSM48_CMODE_SPEECH_V1_VAMOS	= 0xc1,
+	GSM48_CMODE_SPEECH_V2_VAMOS	= 0xc2,
+	GSM48_CMODE_SPEECH_V3_VAMOS	= 0xc3,
+	GSM48_CMODE_SPEECH_V5_VAMOS	= 0xc5,
+};
+
+/* Section 10.5.4.21 / Table 10.5.127 */
+
+enum gsm48_progress_desc {
+	GSM48_PROGR_NOT_E2E		= 0x00,
+	GSM48_PROGR_DEST_NOT_PLMN	= 0x02,
+	GSM48_PROGR_ORIG_NOT_PLMN	= 0x03,
+	GSM48_PROGR_RETURNED		= 0x04,
+	GSM48_PROGR_IN_BAND_AVAIL	= 0x08,
+	GSM48_PROGR_CALL_E2E		= 0x20,
+	GSM48_PROGR_QUEUEING		= 0x40,
+};
+
+/* Section 10.5.4.23 / Table 10.5.130 */
+enum gsm48_signal_val {
+	GSM48_SIGNAL_DIALTONE	= 0x00,
+	GSM48_SIGNAL_RINGBACK	= 0x01,
+	GSM48_SIGNAL_INTERCEPT	= 0x02,
+	GSM48_SIGNAL_NET_CONG	= 0x03,
+	GSM48_SIGNAL_BUSY	= 0x04,
+	GSM48_SIGNAL_CONFIRM	= 0x05,
+	GSM48_SIGNAL_ANSWER	= 0x06,
+	GSM48_SIGNAL_CALL_WAIT	= 0x07,
+	GSM48_SIGNAL_OFF_HOOK	= 0x08,
+	GSM48_SIGNAL_OFF	= 0x3f,
+	GSM48_SIGNAL_ALERT_OFF	= 0x4f,
+};
+
+/* Section 10.5.4.11 / Table 10.5.122 */
+enum gsm48_cause_coding {
+	GSM48_CAUSE_CODING_CCITT_Q931	= 0x00,
+	GSM48_CAUSE_CODING_RESERVED	= 0x01,
+	GSM48_CAUSE_CODING_NATIONAL	= 0x02,
+	GSM48_CAUSE_CODING_GSM		= 0x03,
+};
+
+enum gsm48_cause_loc {
+	GSM48_CAUSE_LOC_USER		= 0x00,
+	GSM48_CAUSE_LOC_PRN_S_LU	= 0x01,
+	GSM48_CAUSE_LOC_PUN_S_LU	= 0x02,
+	GSM48_CAUSE_LOC_TRANS_NET	= 0x03,
+	GSM48_CAUSE_LOC_PUN_S_RU	= 0x04,
+	GSM48_CAUSE_LOC_PRN_S_RU	= 0x05,
+	/* not defined */
+	GSM48_CAUSE_LOC_INN_NET		= 0x07,
+	GSM48_CAUSE_LOC_NET_BEYOND	= 0x0a,
+};
+
+/* Section 10.5.4.11 CC Cause / Table 10.5.123 */
+enum gsm48_cc_cause {
+	GSM48_CC_CAUSE_UNASSIGNED_NR	= 1,
+	GSM48_CC_CAUSE_NO_ROUTE		= 3,
+	GSM48_CC_CAUSE_CHAN_UNACCEPT	= 6,
+	GSM48_CC_CAUSE_OP_DET_BARRING	= 8,
+	GSM48_CC_CAUSE_NORM_CALL_CLEAR	= 16,
+	GSM48_CC_CAUSE_USER_BUSY	= 17,
+	GSM48_CC_CAUSE_USER_NOTRESPOND	= 18,
+	GSM48_CC_CAUSE_USER_ALERTING_NA	= 19,
+	GSM48_CC_CAUSE_CALL_REJECTED	= 21,
+	GSM48_CC_CAUSE_NUMBER_CHANGED	= 22,
+	GSM48_CC_CAUSE_PRE_EMPTION	= 25,
+	GSM48_CC_CAUSE_NONSE_USER_CLR	= 26,
+	GSM48_CC_CAUSE_DEST_OOO		= 27,
+	GSM48_CC_CAUSE_INV_NR_FORMAT	= 28,
+	GSM48_CC_CAUSE_FACILITY_REJ	= 29,
+	GSM48_CC_CAUSE_RESP_STATUS_INQ	= 30,
+	GSM48_CC_CAUSE_NORMAL_UNSPEC	= 31,
+	GSM48_CC_CAUSE_NO_CIRCUIT_CHAN	= 34,
+	GSM48_CC_CAUSE_NETWORK_OOO	= 38,
+	GSM48_CC_CAUSE_TEMP_FAILURE	= 41,
+	GSM48_CC_CAUSE_SWITCH_CONG	= 42,
+	GSM48_CC_CAUSE_ACC_INF_DISCARD	= 43,
+	GSM48_CC_CAUSE_REQ_CHAN_UNAVAIL	= 44,
+	GSM48_CC_CAUSE_RESOURCE_UNAVAIL	= 47,
+	GSM48_CC_CAUSE_QOS_UNAVAIL	= 49,
+	GSM48_CC_CAUSE_REQ_FAC_NOT_SUBSC= 50,
+	GSM48_CC_CAUSE_INC_BARRED_CUG	= 55,
+	GSM48_CC_CAUSE_BEARER_CAP_UNAUTH= 57,
+	GSM48_CC_CAUSE_BEARER_CA_UNAVAIL= 58,
+	GSM48_CC_CAUSE_SERV_OPT_UNAVAIL	= 63,
+	GSM48_CC_CAUSE_BEARERSERV_UNIMPL= 65,
+	GSM48_CC_CAUSE_ACM_GE_ACM_MAX	= 68,
+	GSM48_CC_CAUSE_REQ_FAC_NOTIMPL	= 69,
+	GSM48_CC_CAUSE_RESTR_BCAP_AVAIL	= 70,
+	GSM48_CC_CAUSE_SERV_OPT_UNIMPL	= 79,
+	GSM48_CC_CAUSE_INVAL_TRANS_ID	= 81,
+	GSM48_CC_CAUSE_USER_NOT_IN_CUG	= 87,
+	GSM48_CC_CAUSE_INCOMPAT_DEST	= 88,
+	GSM48_CC_CAUSE_INVAL_TRANS_NET	= 91,
+	GSM48_CC_CAUSE_SEMANTIC_INCORR	= 95,
+	GSM48_CC_CAUSE_INVAL_MAND_INF	= 96,
+	GSM48_CC_CAUSE_MSGTYPE_NOTEXIST	= 97,
+	GSM48_CC_CAUSE_MSGTYPE_INCOMPAT	= 98,
+	GSM48_CC_CAUSE_IE_NOTEXIST	= 99,
+	GSM48_CC_CAUSE_COND_IE_ERR	= 100,
+	GSM48_CC_CAUSE_MSG_INCOMP_STATE	= 101,
+	GSM48_CC_CAUSE_RECOVERY_TIMER	= 102,
+	GSM48_CC_CAUSE_PROTO_ERR	= 111,
+	GSM48_CC_CAUSE_INTERWORKING	= 127,
+};
+
+/* Table 10.5.118 / 3GPP TS 24.008 Section 10.5.4.7 */
+enum gsm48_type_of_number {
+	GSM48_TON_UNKNOWN	= 0,
+	GSM48_TON_INTERNATIONAL	= 1,
+	GSM48_TON_NATIONAL	= 2,
+	GSM48_TON_NET_SPEC	= 3,
+	GSM48_TON_SHORT_CODE	= 4,
+	/* reserved */
+};
+
+/* Table 10.5.118 / 3GPP TS 24.008 Section 10.5.4.7 */
+enum gsm48_numbering_plan {
+	GSM48_NPI_UNKNOWN	= 0,
+	GSM48_NPI_ISDN_E164	= 1,
+	GSM48_NPI_DATA_X121	= 3,
+	GSM48_NPI_TELEX_F69	= 4,
+	GSM48_NPI_NATIONAL	= 8,
+	GSM48_NPI_PRIVATE	= 9,
+	GSM48_NPI_CTS		= 11,
+	/* reserved */
+};
+
+/* local addition, not from Osmocom: Table 10.5.120 from same spec as above */
+
+enum gsm48_present_ind {
+	GSM48_PRES_ALLOW	= 0,
+	GSM48_PRES_RESTR	= 1,
+	GSM48_PRES_UNAVAIL	= 2,
+	/* reserved */
+};
+
+enum gsm48_screen_ind {
+	GSM48_SCRN_USER_NS	= 0,
+	GSM48_SCRN_USER_PASS	= 1,
+	GSM48_SCRN_USER_FAIL	= 2,
+	GSM48_SCRN_NETWORK	= 3,
+};
+
+#endif	/* include guard */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mncc.h	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,349 @@
+/*
+ * This header file defines the MNCC interface for passing call control
+ * into and out of Osmocom GSM network.  It has been put together by
+ * assembling bits from several different Osmocom header files.
+ */
+
+#ifndef	__MNCC_H
+#define	__MNCC_H
+
+#define GSM_MAX_FACILITY       128
+#define GSM_MAX_SSVERSION      128
+#define GSM_MAX_USERUSER       128
+
+/* GSM 04.08 Bearer Capability: Information Transfer Capability */
+enum gsm48_bcap_itcap {
+	GSM48_BCAP_ITCAP_SPEECH		= 0,
+	GSM48_BCAP_ITCAP_UNR_DIG_INF	= 1,
+	GSM48_BCAP_ITCAP_3k1_AUDIO	= 2,
+	GSM48_BCAP_ITCAP_FAX_G3		= 3,
+	GSM48_BCAP_ITCAP_OTHER		= 5,
+	GSM48_BCAP_ITCAP_RESERVED	= 7,
+};
+
+/* GSM 04.08 Bearer Capability: Transfer Mode */
+enum gsm48_bcap_tmod {
+	GSM48_BCAP_TMOD_CIRCUIT		= 0,
+	GSM48_BCAP_TMOD_PACKET		= 1,
+};
+
+/* GSM 04.08 Bearer Capability: Coding Standard */
+enum gsm48_bcap_coding {
+	GSM48_BCAP_CODING_GSM_STD	= 0,
+};
+
+/* GSM 04.08 Bearer Capability: Radio Channel Requirements */
+enum gsm48_bcap_rrq {
+	GSM48_BCAP_RRQ_FR_ONLY	= 1,
+	GSM48_BCAP_RRQ_DUAL_HR	= 2,
+	GSM48_BCAP_RRQ_DUAL_FR	= 3,
+};
+
+/* GSM 04.08 Bearer Capability: Rate Adaption */
+enum gsm48_bcap_ra {
+	GSM48_BCAP_RA_NONE	= 0,
+	GSM48_BCAP_RA_V110_X30	= 1,
+	GSM48_BCAP_RA_X31	= 2,
+	GSM48_BCAP_RA_OTHER	= 3,
+};
+
+/* GSM 04.08 Bearer Capability: Signalling access protocol */
+enum gsm48_bcap_sig_access {
+	GSM48_BCAP_SA_I440_I450	= 1,
+	GSM48_BCAP_SA_X21	= 2,
+	GSM48_BCAP_SA_X28_DP_IN	= 3,
+	GSM48_BCAP_SA_X28_DP_UN	= 4,
+	GSM48_BCAP_SA_X28_NDP	= 5,
+	GSM48_BCAP_SA_X32	= 6,
+};
+
+/* GSM 04.08 Bearer Capability: User Rate */
+enum gsm48_bcap_user_rate {
+	GSM48_BCAP_UR_300	= 1,
+	GSM48_BCAP_UR_1200	= 2,
+	GSM48_BCAP_UR_2400	= 3,
+	GSM48_BCAP_UR_4800	= 4,
+	GSM48_BCAP_UR_9600	= 5,
+	GSM48_BCAP_UR_12000	= 6,
+	GSM48_BCAP_UR_1200_75	= 7,
+};
+
+/* GSM 04.08 Bearer Capability: Parity */
+enum gsm48_bcap_parity {
+	GSM48_BCAP_PAR_ODD	= 0,
+	GSM48_BCAP_PAR_EVEN	= 2,
+	GSM48_BCAP_PAR_NONE	= 3,
+	GSM48_BCAP_PAR_ZERO	= 4,
+	GSM48_BCAP_PAR_ONE	= 5,
+};
+
+/* GSM 04.08 Bearer Capability: Intermediate Rate */
+enum gsm48_bcap_interm_rate {
+	GSM48_BCAP_IR_8k	= 2,
+	GSM48_BCAP_IR_16k	= 3,
+};
+
+/* GSM 04.08 Bearer Capability: Transparency */
+enum gsm48_bcap_transp {
+	GSM48_BCAP_TR_TRANSP	= 0,
+	GSM48_BCAP_TR_RLP	= 1,
+	GSM48_BCAP_TR_TR_PREF	= 2,
+	GSM48_BCAP_TR_RLP_PREF	= 3,
+};
+
+/* GSM 04.08 Bearer Capability: Modem Type */
+enum gsm48_bcap_modem_type {
+	GSM48_BCAP_MT_NONE	= 0,
+	GSM48_BCAP_MT_V21	= 1,
+	GSM48_BCAP_MT_V22	= 2,
+	GSM48_BCAP_MT_V22bis	= 3,
+	GSM48_BCAP_MT_V23	= 4,
+	GSM48_BCAP_MT_V26ter	= 5,
+	GSM48_BCAP_MT_V32	= 6,
+	GSM48_BCAP_MT_UNDEF	= 7,
+	GSM48_BCAP_MT_AUTO_1	= 8,
+};
+
+/*! GSM 04.08 Bearer Capability: Speech Version Indication
+ *  (See also 3GPP TS 24.008, Table 10.5.103) */
+enum gsm48_bcap_speech_ver {
+	GSM48_BCAP_SV_FR	= 0,	/*!< GSM FR V1 (GSM FR) */
+	GSM48_BCAP_SV_HR	= 1,	/*!< GSM HR V1 (GSM HR) */
+	GSM48_BCAP_SV_EFR	= 2,	/*!< GSM FR V2 (GSM EFR) */
+	GSM48_BCAP_SV_AMR_F	= 4,	/*!< GSM FR V3 (FR AMR) */
+	GSM48_BCAP_SV_AMR_H	= 5,	/*!< GSM HR V3 (HR_AMR) */
+	GSM48_BCAP_SV_AMR_OFW	= 6,	/*!< GSM FR V4 (OFR AMR-WB) */
+	GSM48_BCAP_SV_AMR_OHW	= 7,	/*!< GSM HR V4 (OHR AMR-WB) */
+	GSM48_BCAP_SV_AMR_FW	= 8,	/*!< GSM FR V5 (FR AMR-WB) */
+	GSM48_BCAP_SV_AMR_OH	= 11,	/*!< GSM HR V6 (OHR AMR) */
+};
+
+/* Expanded fields from GSM TS 04.08, Table 10.5.102 */
+struct gsm_mncc_bearer_cap {
+	int		transfer;	/* Information Transfer Capability, see enum gsm48_bcap_itcap. */
+	int 		mode;		/* Transfer Mode, see enum gsm48_bcap_tmod. */
+	int		coding;		/* Coding Standard, see enum gsm48_bcap_coding.*/
+	int		radio;		/* Radio Channel Requirement, see enum gsm48_bcap_rrq. */
+	int		speech_ctm;	/* CTM text telephony indication */
+	int		speech_ver[8];	/* Speech version indication, see enum gsm48_bcap_speech_ver; -1 marks end */
+	struct {
+		enum gsm48_bcap_ra		rate_adaption;
+		enum gsm48_bcap_sig_access	sig_access;
+		int				async;
+		int				nr_stop_bits;
+		int				nr_data_bits;
+		enum gsm48_bcap_user_rate	user_rate;
+		enum gsm48_bcap_parity		parity;
+		enum gsm48_bcap_interm_rate	interm_rate;
+		enum gsm48_bcap_transp		transp;
+		enum gsm48_bcap_modem_type	modem_type;
+	} data;
+};
+
+struct gsm_mncc_number {
+	int 		type;
+	int 		plan;
+	int		present;
+	int		screen;
+	char		number[33];
+};
+
+struct gsm_mncc_cause {
+	int		location;
+	int		coding;
+	int		rec;
+	int		rec_val;
+	int		value;
+	int		diag_len;
+	char		diag[32];
+};
+
+struct gsm_mncc_useruser {
+	int		proto;
+	char		info[GSM_MAX_USERUSER + 1]; /* + termination char */
+};
+
+struct gsm_mncc_progress {
+	int		coding;
+	int		location;
+	int 		descr;
+};
+
+struct gsm_mncc_facility {
+	int		len;
+	char		info[GSM_MAX_FACILITY];
+};
+
+struct gsm_mncc_ssversion {
+	int		len;
+	char		info[GSM_MAX_SSVERSION];
+};
+
+struct gsm_mncc_cccap {
+	int		dtmf;
+	int		pcp;
+};
+
+#define MNCC_SETUP_REQ		0x0101
+#define MNCC_SETUP_IND		0x0102
+#define MNCC_SETUP_RSP		0x0103
+#define MNCC_SETUP_CNF		0x0104
+#define MNCC_SETUP_COMPL_REQ	0x0105
+#define MNCC_SETUP_COMPL_IND	0x0106
+/* MNCC_REJ_* is performed via MNCC_REL_* */
+#define MNCC_CALL_CONF_IND	0x0107
+#define MNCC_CALL_PROC_REQ	0x0108
+#define MNCC_PROGRESS_REQ	0x0109
+#define MNCC_ALERT_REQ		0x010a
+#define MNCC_ALERT_IND		0x010b
+#define MNCC_NOTIFY_REQ		0x010c
+#define MNCC_NOTIFY_IND		0x010d
+#define MNCC_DISC_REQ		0x010e
+#define MNCC_DISC_IND		0x010f
+#define MNCC_REL_REQ		0x0110
+#define MNCC_REL_IND		0x0111
+#define MNCC_REL_CNF		0x0112
+#define MNCC_FACILITY_REQ	0x0113
+#define MNCC_FACILITY_IND	0x0114
+#define MNCC_START_DTMF_IND	0x0115
+#define MNCC_START_DTMF_RSP	0x0116
+#define MNCC_START_DTMF_REJ	0x0117
+#define MNCC_STOP_DTMF_IND	0x0118
+#define MNCC_STOP_DTMF_RSP	0x0119
+#define MNCC_MODIFY_REQ		0x011a
+#define MNCC_MODIFY_IND		0x011b
+#define MNCC_MODIFY_RSP		0x011c
+#define MNCC_MODIFY_CNF		0x011d
+#define MNCC_MODIFY_REJ		0x011e
+#define MNCC_HOLD_IND		0x011f
+#define MNCC_HOLD_CNF		0x0120
+#define MNCC_HOLD_REJ		0x0121
+#define MNCC_RETRIEVE_IND	0x0122
+#define MNCC_RETRIEVE_CNF	0x0123
+#define MNCC_RETRIEVE_REJ	0x0124
+#define MNCC_USERINFO_REQ	0x0125
+#define MNCC_USERINFO_IND	0x0126
+#define MNCC_REJ_REQ		0x0127
+#define MNCC_REJ_IND		0x0128
+
+#define MNCC_BRIDGE		0x0200
+#define MNCC_FRAME_RECV		0x0201
+#define MNCC_FRAME_DROP		0x0202
+#define MNCC_LCHAN_MODIFY	0x0203
+#define MNCC_RTP_CREATE		0x0204
+#define MNCC_RTP_CONNECT	0x0205
+#define MNCC_RTP_FREE		0x0206
+
+#define GSM_TCHF_FRAME		0x0300
+#define GSM_TCHF_FRAME_EFR	0x0301
+#define GSM_TCHH_FRAME		0x0302
+#define GSM_TCH_FRAME_AMR	0x0303
+#define GSM_BAD_FRAME		0x03ff
+
+#define MNCC_SOCKET_HELLO	0x0400
+
+#define	MNCC_F_BEARER_CAP	0x0001
+#define MNCC_F_CALLED		0x0002
+#define MNCC_F_CALLING		0x0004
+#define MNCC_F_REDIRECTING	0x0008
+#define MNCC_F_CONNECTED	0x0010
+#define MNCC_F_CAUSE		0x0020
+#define MNCC_F_USERUSER		0x0040
+#define MNCC_F_PROGRESS		0x0080
+#define MNCC_F_EMERGENCY	0x0100
+#define MNCC_F_FACILITY		0x0200
+#define MNCC_F_SSVERSION	0x0400
+#define MNCC_F_CCCAP		0x0800
+#define MNCC_F_KEYPAD		0x1000
+#define MNCC_F_SIGNAL		0x2000
+#define MNCC_F_GCR		0x4000
+
+struct gsm_mncc {
+	/* context based information */
+	uint32_t	msg_type;
+	uint32_t	callref;
+
+	/* which fields are present */
+	uint32_t	fields;
+
+	/* data derived information (MNCC_F_ based) */
+	struct gsm_mncc_bearer_cap	bearer_cap;
+	struct gsm_mncc_number		called;
+	struct gsm_mncc_number		calling;
+	struct gsm_mncc_number		redirecting;
+	struct gsm_mncc_number		connected;
+	struct gsm_mncc_cause		cause;
+	struct gsm_mncc_progress	progress;
+	struct gsm_mncc_useruser	useruser;
+	struct gsm_mncc_facility	facility;
+	struct gsm_mncc_cccap		cccap;
+	struct gsm_mncc_ssversion	ssversion;
+	struct	{
+		int		sup;
+		int		inv;
+	} clir;
+	int		signal;
+
+	/* data derived information, not MNCC_F based */
+	int		keypad;
+	int		more;
+	int		notify; /* 0..127 */
+	int		emergency;
+	char		imsi[16];
+
+	unsigned char	lchan_type;
+	unsigned char	lchan_mode;
+
+	/* Global Call Reference (encoded as per 3GPP TS 29.205) */
+	uint8_t		gcr[16];
+
+	/* A buffer to contain SDP ('\0' terminated) */
+	char		sdp[1024];
+};
+
+struct gsm_data_frame {
+	uint32_t	msg_type;
+	uint32_t	callref;
+	unsigned char	data[0];
+};
+
+#define MNCC_SOCK_VERSION	8
+struct gsm_mncc_hello {
+	uint32_t	msg_type;
+	uint32_t	version;
+
+	/* send the sizes of the structs */
+	uint32_t	mncc_size;
+	uint32_t	data_frame_size;
+
+	/* send some offsets */
+	uint32_t	called_offset;
+	uint32_t	signal_offset;
+	uint32_t	emergency_offset;
+	uint32_t	lchan_type_offset;
+};
+
+struct gsm_mncc_rtp {
+	uint32_t	msg_type;
+	uint32_t	callref;
+	struct sockaddr_storage addr;
+	uint32_t	payload_type;
+	uint32_t	payload_msg_type;
+	char		sdp[1024];
+};
+
+struct gsm_mncc_bridge {
+	uint32_t	msg_type;
+	uint32_t	callref[2];
+};
+
+union mncc_msg {
+	uint32_t msg_type;
+	struct gsm_mncc signal;
+	struct gsm_mncc_hello hello;
+	struct gsm_data_frame data_frame;
+	struct gsm_mncc_rtp rtp;
+	struct gsm_mncc_bridge bridge;
+};
+
+#endif	/* include guard */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/Makefile	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,14 @@
+OBJS=	dtmf_valid.o extdigits.o imsi_entry.o mncc_debug.o mncc_utils.o \
+	sockinit.o
+LIB=	libutil.a
+
+include ../config.defs
+
+all:	${LIB}
+
+${LIB}:	${OBJS}
+	ar rcu $@ ${OBJS}
+	ranlib $@
+
+clean:
+	rm -f *.[oa] errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/dtmf_valid.c	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,29 @@
+/*
+ * Here we implement a function that validates DTMF digits which arrive
+ * from GSM MS via MNCC_START_DTMF_IND.
+ */
+
+is_valid_dtmf_digit(c)
+{
+	switch (c) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	case '*':
+	case '#':
+	case 'A':
+	case 'B':
+	case 'C':
+	case 'D':
+		return(1);
+	default:
+		return(0);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/extdigits.c	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,29 @@
+/*
+ * The library function implemented in this module checks "extended"
+ * number digits, i.e., checks whether or not a given character
+ * makes a valid "extended" number digit.
+ */
+
+is_valid_ext_digit(c)
+{
+	switch (c) {
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	case '*':
+	case '#':
+	case 'a':
+	case 'b':
+	case 'c':
+		return(1);
+	default:
+		return(0);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/imsi_entry.c	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,54 @@
+/*
+ * The library function implemented in this module supports IMSI entry
+ * at UI level, either in the standard form (long string of digits)
+ * or in the shorthand notation introduced in fc-sim-tools.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+
+grok_imsi_user_arg(arg, dest)
+	char *arg, *dest;
+{
+	char *cp, *dp;
+	int n, tail_len, remain;
+
+	if (!isdigit(*arg))
+		return(-1);
+	cp = arg;
+	dp = dest;
+	n = 0;
+	while (isdigit(*cp)) {
+		if (n >= 15)
+			return(-1);
+		*dp++ = *cp++;
+		n++;
+	}
+	if (!*cp) {
+		if (n < 6)
+			return(-1);
+		*dp = '\0';
+		return(0);
+	}
+	if (*cp != '-')
+		return(-1);
+	cp++;
+	tail_len = strlen(cp);
+	if (!tail_len)
+		return(-1);
+	remain = 15 - n;
+	if (remain < tail_len + 1)
+		return(-1);
+	while (remain > tail_len) {
+		*dp++ = '0';
+		remain--;
+	}
+	while (*cp) {
+		if (!isdigit(*cp))
+			return(-1);
+		*dp++ = *cp++;
+	}
+	*dp = '\0';
+	return(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/mncc_debug.c	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,109 @@
+/* MNCC debug functions */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdint.h>
+#include "../include/mncc.h"
+
+char *
+mncc_msg_name(msgtype)
+{
+	static char buf[32];
+
+	switch (msgtype) {
+	case MNCC_SETUP_REQ:
+		return "MNCC_SETUP_REQ";
+	case MNCC_SETUP_IND:
+		return "MNCC_SETUP_IND";
+	case MNCC_SETUP_RSP:
+		return "MNCC_SETUP_RSP";
+	case MNCC_SETUP_CNF:
+		return "MNCC_SETUP_CNF";
+	case MNCC_SETUP_COMPL_REQ:
+		return "MNCC_SETUP_COMPL_REQ";
+	case MNCC_SETUP_COMPL_IND:
+		return "MNCC_SETUP_COMPL_IND";
+	case MNCC_CALL_CONF_IND:
+		return "MNCC_CALL_CONF_IND";
+	case MNCC_CALL_PROC_REQ:
+		return "MNCC_CALL_PROC_REQ";
+	case MNCC_PROGRESS_REQ:
+		return "MNCC_PROGRESS_REQ";
+	case MNCC_ALERT_REQ:
+		return "MNCC_ALERT_REQ";
+	case MNCC_ALERT_IND:
+		return "MNCC_ALERT_IND";
+	case MNCC_NOTIFY_REQ:
+		return "MNCC_NOTIFY_REQ";
+	case MNCC_NOTIFY_IND:
+		return "MNCC_NOTIFY_IND";
+	case MNCC_DISC_REQ:
+		return "MNCC_DISC_REQ";
+	case MNCC_DISC_IND:
+		return "MNCC_DISC_IND";
+	case MNCC_REL_REQ:
+		return "MNCC_REL_REQ";
+	case MNCC_REL_IND:
+		return "MNCC_REL_IND";
+	case MNCC_REL_CNF:
+		return "MNCC_REL_CNF";
+	case MNCC_FACILITY_REQ:
+		return "MNCC_FACILITY_REQ";
+	case MNCC_FACILITY_IND:
+		return "MNCC_FACILITY_IND";
+	case MNCC_START_DTMF_IND:
+		return "MNCC_START_DTMF_IND";
+	case MNCC_START_DTMF_RSP:
+		return "MNCC_START_DTMF_RSP";
+	case MNCC_START_DTMF_REJ:
+		return "MNCC_START_DTMF_REJ";
+	case MNCC_STOP_DTMF_IND:
+		return "MNCC_STOP_DTMF_IND";
+	case MNCC_STOP_DTMF_RSP:
+		return "MNCC_STOP_DTMF_RSP";
+	case MNCC_MODIFY_REQ:
+		return "MNCC_MODIFY_REQ";
+	case MNCC_MODIFY_IND:
+		return "MNCC_MODIFY_IND";
+	case MNCC_MODIFY_RSP:
+		return "MNCC_MODIFY_RSP";
+	case MNCC_MODIFY_CNF:
+		return "MNCC_MODIFY_CNF";
+	case MNCC_MODIFY_REJ:
+		return "MNCC_MODIFY_REJ";
+	case MNCC_HOLD_IND:
+		return "MNCC_HOLD_IND";
+	case MNCC_HOLD_CNF:
+		return "MNCC_HOLD_CNF";
+	case MNCC_HOLD_REJ:
+		return "MNCC_HOLD_REJ";
+	case MNCC_RETRIEVE_IND:
+		return "MNCC_RETRIEVE_IND";
+	case MNCC_RETRIEVE_CNF:
+		return "MNCC_RETRIEVE_CNF";
+	case MNCC_RETRIEVE_REJ:
+		return "MNCC_RETRIEVE_REJ";
+	case MNCC_USERINFO_REQ:
+		return "MNCC_USERINFO_REQ";
+	case MNCC_USERINFO_IND:
+		return "MNCC_USERINFO_IND";
+	case MNCC_REJ_REQ:
+		return "MNCC_REJ_REQ";
+	case MNCC_REJ_IND:
+		return "MNCC_REJ_IND";
+	case MNCC_BRIDGE:
+		return "MNCC_BRIDGE";
+	case MNCC_RTP_CREATE:
+		return "MNCC_RTP_CREATE";
+	case MNCC_RTP_CONNECT:
+		return "MNCC_RTP_CONNECT";
+	case MNCC_RTP_FREE:
+		return "MNCC_RTP_FREE";
+	case MNCC_SOCKET_HELLO:
+		return "MNCC_SOCKET_HELLO";
+	default:
+		sprintf(buf, "MNCC msgtype 0x%x", msgtype);
+		return buf;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/mncc_utils.c	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,18 @@
+/* simple utility functions for MNCC */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "../include/mncc.h"
+#include "../include/gsm48_const.h"
+
+mncc_set_cause(msg, loc, val)
+	struct gsm_mncc *msg;
+{
+	msg->fields |= MNCC_F_CAUSE;
+	msg->cause.coding = GSM48_CAUSE_CODING_GSM;
+	msg->cause.location = loc;
+	msg->cause.value = val;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libutil/sockinit.c	Sat Jun 08 23:06:53 2024 +0000
@@ -0,0 +1,40 @@
+/*
+ * This library module implements a function that helps initialize
+ * sockaddr for bind or connect operations on UNIX domain sockets.
+ *
+ * Back when I programmed under 4.3BSD UNIX, this operation was simple
+ * and straightforward - but under "modern" Unixes, it appears to be
+ * a complex affair, given the messy code (originally copied from
+ * Osmocom) that appears in FreeCalypso host tools for the rvinterf
+ * local socket interface.  Hence I am factoring that mess out into
+ * its own library function this time around.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+#include <strings.h>
+
+void
+fill_sockaddr_un(pathname, sunp, lenp)
+	char *pathname;
+	struct sockaddr_un *sunp;
+	unsigned *lenp;
+{
+	/* local socket binding voodoo copied from osmocon */
+	sunp->sun_family = AF_UNIX;
+	strncpy(sunp->sun_path, pathname, sizeof(sunp->sun_path));
+	sunp->sun_path[sizeof(sunp->sun_path) - 1] = '\0';
+	/* we use the same magic that X11 uses in Xtranssock.c for
+	 * calculating the proper length of the sockaddr */
+#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
+	sunp->sun_len = strlen(sunp->sun_path);
+#endif
+#if defined(BSD44SOCKETS) || defined(SUN_LEN)
+	*lenp = SUN_LEN(sunp);
+#else
+	*lenp = strlen(sunp->sun_path) +
+		offsetof(struct sockaddr_un, sun_path) + 1;
+#endif
+}