summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile.in19
-rw-r--r--src/cc.c1128
-rw-r--r--src/ccitt-adpcm/README94
-rw-r--r--src/ccitt-adpcm/decode.c113
-rw-r--r--src/ccitt-adpcm/encode.c119
-rw-r--r--src/ccitt-adpcm/g711.c285
-rw-r--r--src/ccitt-adpcm/g721.c173
-rw-r--r--src/ccitt-adpcm/g723_24.c158
-rw-r--r--src/ccitt-adpcm/g723_40.c178
-rw-r--r--src/ccitt-adpcm/g72x.c565
-rw-r--r--src/ccitt-adpcm/g72x.h148
-rw-r--r--src/dsaa.c211
-rw-r--r--src/identities.c182
-rw-r--r--src/keypad.c80
-rw-r--r--src/lce.c790
-rw-r--r--src/libdect.c81
-rw-r--r--src/mm.c154
-rw-r--r--src/netlink.c139
-rw-r--r--src/s_msg.c991
-rw-r--r--src/ss.c49
-rw-r--r--src/utils.c142
22 files changed, 5800 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..bd99de1
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1 @@
+libdect.so
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..0a12706
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,19 @@
+CFLAGS += -fPIC
+LIBS += dect
+
+dect-destdir := usr/lib
+
+dect-obj += libdect.o
+dect-obj += identities.o
+dect-obj += s_msg.o
+dect-obj += lce.o
+dect-obj += cc.o
+dect-obj += ss.o
+dect-obj += keypad.o
+dect-obj += dsaa.o
+dect-obj += netlink.o
+dect-obj += utils.o
+
+dect-obj += ccitt-adpcm/g711.o
+dect-obj += ccitt-adpcm/g72x.o
+dect-obj += ccitt-adpcm/g721.o
diff --git a/src/cc.c b/src/cc.c
new file mode 100644
index 0000000..062f2ad
--- /dev/null
+++ b/src/cc.c
@@ -0,0 +1,1128 @@
+/*
+ * DECT Call Control (CC)
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/dect.h>
+
+#include <libdect.h>
+#include <utils.h>
+#include <s_fmt.h>
+#include <lce.h>
+#include <cc.h>
+
+static const struct dect_sfmt_ie_desc cc_setup_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_MANDATORY, IE_MANDATORY, 0),
+ DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_MANDATORY, IE_MANDATORY, 0),
+ DECT_SFMT_IE(S_VL_IE_NWK_ASSIGNED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_DO_IE_BASIC_SERVICE, IE_MANDATORY, IE_MANDATORY, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_CIPHER_INFO, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_IDENTITY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_PROGRESS_INDICATOR, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_KEYPAD, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_DO_IE_SIGNAL, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_ACTIVATE, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_NETWORK_PARAMETER, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_EXT_HO_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_TERMINAL_CAPABILITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_END_TO_END_COMPATIBILITY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_RATE_PARAMETERS, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_TRANSIT_DELAY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_WINDOW_SIZE, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLING_PARTY_NUMBER, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLED_PARTY_NUMBER, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLED_PARTY_SUBADDR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SE_IE_SENDING_COMPLETE, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_SEGMENTED_INFO, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLING_PARTY_NAME, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_INFORMATION, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_info_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_LOCATION_AREA, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_NWK_ASSIGNED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_PROGRESS_INDICATOR, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_KEYPAD, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_DO_IE_SIGNAL, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_ACTIVATE, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_NETWORK_PARAMETER, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_EXT_HO_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLING_PARTY_NUMBER, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLED_PARTY_NUMBER, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLED_PARTY_SUBADDR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SE_IE_SENDING_COMPLETE, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_DO_IE_TEST_HOOK_CONTROL, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALLING_PARTY_NAME, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_INFORMATION, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_setup_ack_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_INFO_TYPE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_LOCATION_AREA, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_ATTRIBUTES, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_ATTRIBUTES, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_ATTRIBUTES, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_IDENTITY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_PROGRESS_INDICATOR, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_DO_IE_SIGNAL, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_NETWORK_PARAMETER, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_EXT_HO_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_TRANSIT_DELAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_WINDOW_SIZE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SE_IE_DELIMITER_REQUEST, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_call_proc_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_IWU_ATTRIBUTES, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_ATTRIBUTES, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_ATTRIBUTES, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_IDENTITY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_PROGRESS_INDICATOR, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_DO_IE_SIGNAL, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_TRANSIT_DELAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_WINDOW_SIZE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_alerting_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_IWU_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_IDENTITY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_PROGRESS_INDICATOR, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_DO_IE_SIGNAL, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_TERMINAL_CAPABILITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_TRANSIT_DELAY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_WINDOW_SIZE, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_connect_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_IWU_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_IDENTITY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_PROGRESS_INDICATOR, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_DO_IE_SIGNAL, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_NETWORK_PARAMETER, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_EXT_HO_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_TERMINAL_CAPABILITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_TRANSIT_DELAY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_WINDOW_SIZE, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_SEGMENTED_INFO, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_connect_ack_msg_desc[] = {
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_release_msg_desc[] = {
+ DECT_SFMT_IE(S_DO_IE_RELEASE_REASON, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_PROGRESS_INDICATOR, IE_OPTIONAL, IE_NONE, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_SEGMENTED_INFO, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_release_com_msg_desc[] = {
+ DECT_SFMT_IE(S_DO_IE_RELEASE_REASON, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IDENTITY_TYPE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_LOCATION_AREA, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CONNECTION_ATTRIBUTES, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_NETWORK_PARAMETER, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_SO_IE_REPEAT_INDICATOR, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_SEGMENTED_INFO, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_PACKET, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_service_change_msg_desc[] = {
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_service_accept_msg_desc[] = {
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_service_reject_msg_desc[] = {
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_notify_msg_desc[] = {
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc cc_iwu_info_msg_desc[] = {
+ DECT_SFMT_IE_END_MSG
+};
+
+#define cc_debug(call, fmt, args...) \
+ dect_debug("CC: call %p (%s): " fmt "\n", \
+ (call), call_states[(call)->state], ## args)
+
+static const char *call_states[DECT_CC_STATE_MAX + 1] = {
+ [DECT_CC_CALL_INITIATED] = "CALL INITIATED",
+ [DECT_CC_OVERLAP_SENDING] = "OVERLAP SENDING",
+ [DECT_CC_CALL_PROCEEDING] = "CALL PROCEEDING",
+ [DECT_CC_CALL_DELIVERED] = "CALL DELIVERED",
+ [DECT_CC_CALL_PRESENT] = "CALL PRESENT",
+ [DECT_CC_CALL_RECEIVED] = "CALL RECEIVED",
+ [DECT_CC_CONNECT_PENDING] = "CONNECT PENDING",
+ [DECT_CC_ACTIVE] = "ACTIVE",
+ [DECT_CC_RELEASE_PENDING] = "RELEASE PENDING",
+ [DECT_CC_OVERLAP_RECEIVING] = "OVERLAP RECEIVING",
+ [DECT_CC_INCOMING_CALL_PROCEEDING] = "INCOMING CALL PROCEEDING",
+};
+
+void *dect_call_priv(struct dect_call *call)
+{
+ return call->priv;
+}
+
+const struct dect_ipui *dect_call_portable_identity(const struct dect_call *call)
+{
+ return &call->pt_id->ipui;
+}
+
+int dect_dl_u_data_req(const struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ ssize_t size;
+
+ if (call->lu_sap == NULL) {
+ cc_debug(call, "U-Plane U_DATA-req, but still unconnected");
+ return 0;
+ }
+ //cc_debug(call, "U-Plane U_DATA-req");
+ //dect_mbuf_dump(mb, "LU1");
+ size = send(call->lu_sap->fd, mb->data, mb->len, 0);
+ if (size != ((ssize_t)mb->len))
+ cc_debug(call, "sending %u bytes failed: err=%d\n",
+ mb->len, errno);
+ return 0;
+}
+
+static void dect_cc_lu_event(struct dect_handle *dh, struct dect_fd *fd,
+ uint32_t event)
+{
+ struct dect_call *call = fd->data;
+ struct dect_msg_buf *mb;
+ ssize_t len;
+
+ //cc_debug(call, "U-Plane U_DATA-ind");
+ mb = dect_mbuf_alloc(dh);
+ if (mb == NULL)
+ return;
+
+ len = recv(call->lu_sap->fd, mb->data, sizeof(mb->head), 0);
+ if (len < 0)
+ return;
+ mb->len = len;
+
+ //dect_mbuf_dump(mb, "LU1");
+ dh->ops->cc_ops->dl_u_data_ind(dh, call, mb);
+}
+
+static int dect_call_connect_uplane(const struct dect_handle *dh,
+ struct dect_call *call)
+{
+ struct sockaddr_dect_lu addr;
+
+ call->lu_sap = dect_socket(dh, SOCK_STREAM, DECT_LU1_SAP);
+ if (call->lu_sap == NULL)
+ goto err1;
+
+ dect_transaction_get_ulei(&addr, &call->transaction);
+ if (connect(call->lu_sap->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ goto err2;
+
+ call->lu_sap->data = call;
+ call->lu_sap->callback = dect_cc_lu_event;
+ if (dect_register_fd(dh, call->lu_sap, DECT_FD_READ) < 0)
+ goto err2;
+ cc_debug(call, "U-Plane connected");
+ return 0;
+
+err2:
+ dect_close(dh, call->lu_sap);
+ call->lu_sap = NULL;
+err1:
+ cc_debug(call, "U-Plane connect failed: %s", strerror(errno));
+ return -1;
+}
+
+static void dect_call_disconnect_uplane(const struct dect_handle *dh,
+ struct dect_call *call)
+{
+ dect_unregister_fd(dh, call->lu_sap);
+ dect_close(dh, call->lu_sap);
+ call->lu_sap = NULL;
+}
+
+struct dect_call *dect_call_alloc(const struct dect_handle *dh)
+{
+ struct dect_call *call;
+
+ call = dect_zalloc(dh, sizeof(*call) + dh->ops->cc_ops->priv_size);
+ if (call == NULL)
+ goto err1;
+
+ call->setup_timer = dect_alloc_timer(dh);
+ if (call->setup_timer == NULL)
+ goto err2;
+ call->setup_timer->data = call;
+
+ call->state = DECT_CC_NULL;
+ return call;
+
+err2:
+ dect_free(dh, call);
+err1:
+ return NULL;
+}
+
+static void dect_call_destroy(const struct dect_handle *dh,
+ struct dect_call *call)
+{
+ if (call->state == DECT_CC_CALL_PRESENT)
+ dect_stop_timer(dh, call->setup_timer);
+ dect_free(dh, call->setup_timer);
+ dect_free(dh, call);
+}
+
+static int dect_cc_send_msg(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_sfmt_ie_desc *desc,
+ const struct dect_msg_common *msg,
+ enum dect_cc_msg_types type, const char *prefix)
+{
+ return dect_lce_send(dh, &call->transaction, desc, msg, type, prefix);
+}
+
+static void dect_cc_setup_timer(struct dect_handle *dh, struct dect_timer *timer)
+{
+ struct dect_call *call = timer->data;
+ struct dect_ie_release_reason release_reason;
+ struct dect_mncc_release_param param = {
+ .release_reason = &release_reason,
+ };
+
+ cc_debug(call, "setup timer");
+ // release-com
+
+ dect_ie_init(&release_reason);
+ release_reason.reason = DECT_RELEASE_TIMER_EXPIRY;
+ dh->ops->cc_ops->mncc_reject_ind(dh, call, &param);
+
+ dect_close_transaction(dh, &call->transaction);
+ dect_call_destroy(dh, call);
+}
+
+int dect_mncc_setup_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_ipui *ipui,
+ const struct dect_mncc_setup_param *param)
+{
+ struct dect_ie_portable_identity portable_identity;
+ struct dect_ie_fixed_identity fixed_identity;
+ struct dect_cc_setup_msg msg = {
+ .portable_identity = &portable_identity,
+ .fixed_identity = &fixed_identity,
+ .basic_service = param->basic_service,
+ .iwu_attributes = param->iwu_attributes,
+ .cipher_info = param->cipher_info,
+ .facility = param->facility,
+ .progress_indicator = param->progress_indicator,
+ .display = param->display,
+ .keypad = param->keypad,
+ .signal = param->signal,
+ .feature_activate = param->feature_activate,
+ .feature_indicate = param->feature_indicate,
+ .network_parameter = param->network_parameter,
+ .terminal_capability = param->terminal_capability,
+ .end_to_end_compatibility = param->end_to_end_compatibility,
+ .rate_parameters = param->rate_parameters,
+ .transit_delay = param->transit_delay,
+ .window_size = param->window_size,
+ .calling_party_number = param->calling_party_number,
+ .called_party_number = param->called_party_number,
+ .called_party_subaddress = param->called_party_subaddress,
+ .calling_party_name = param->calling_party_name,
+ .sending_complete = param->sending_complete,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ cc_debug(call, "setup request");
+
+ call->transaction.pd = DECT_S_PD_CC;
+ if (dect_open_transaction(dh, &call->transaction, ipui) < 0)
+ goto err1;
+
+ fixed_identity.type = ID_TYPE_PARK;
+ memcpy(&fixed_identity.ari, &dh->pari, sizeof(fixed_identity.ari));
+ portable_identity.type = ID_TYPE_IPUI;
+ portable_identity.ipui = *ipui;
+
+ if (dect_cc_send_msg(dh, call, cc_setup_msg_desc, &msg.common,
+ CC_SETUP, "CC-SETUP") < 0)
+ goto err2;
+ call->state = DECT_CC_CALL_PRESENT;
+
+ call->setup_timer->callback = dect_cc_setup_timer;
+ dect_start_timer(dh, call->setup_timer, DECT_CC_SETUP_TIMEOUT);
+ return 0;
+
+err2:
+ dect_close_transaction(dh, &call->transaction);
+err1:
+ return -1;
+}
+
+int dect_mncc_setup_ack_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_setup_ack_param *param)
+{
+ struct dect_cc_setup_ack_msg msg = {
+ .portable_identity = call->pt_id,
+ .fixed_identity = call->ft_id,
+ .info_type = param->info_type,
+ .location_area = param->location_area,
+ .display = param->display,
+ .signal = param->signal,
+ .feature_indicate = param->feature_indicate,
+ .transit_delay = param->transit_delay,
+ .window_size = param->window_size,
+ .delimiter_request = param->delimiter_request,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ dect_cc_send_msg(dh, call, cc_setup_ack_msg_desc, &msg.common,
+ CC_SETUP_ACK, "CC-SETUP_ACK");
+ return 0;
+}
+
+int dect_mncc_reject_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_call_proc_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_call_proc_param *param)
+{
+ struct dect_cc_call_proc_msg msg = {
+ .facility = param->facility,
+ .progress_indicator = param->progress_indicator,
+ .display = param->display,
+ .signal = param->signal,
+ .feature_indicate = param->feature_indicate,
+ .transit_delay = param->transit_delay,
+ .window_size = param->window_size,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ dect_cc_send_msg(dh, call, cc_call_proc_msg_desc, &msg.common,
+ CC_CALL_PROC, "CC-CALL_PROC");
+ return 0;
+}
+int dect_mncc_alert_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_alert_param *param)
+{
+ struct dect_cc_alerting_msg msg = {
+ .facility = param->facility,
+ //.progress_indicator = param->progress_indicator,
+ .display = param->display,
+ .signal = param->signal,
+ .feature_indicate = param->feature_indicate,
+ .terminal_capability = param->terminal_capability,
+ .transit_delay = param->transit_delay,
+ .window_size = param->window_size,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ // FIXME FIXME FIXME FIXME
+ if (param->progress_indicator.list.next != NULL) {
+ init_list_head(&msg.progress_indicator.list);
+ dect_ie_list_move(&msg.progress_indicator,
+ (struct dect_ie_repeat_indicator *)&param->progress_indicator);
+ }
+
+ dect_cc_send_msg(dh, call, cc_alerting_msg_desc, &msg.common,
+ CC_ALERTING, "CC-ALERTING");
+ return 0;
+}
+
+int dect_mncc_connect_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_connect_param *param)
+{
+ struct dect_cc_connect_msg msg = {
+ .facility = param->facility,
+ .progress_indicator = param->progress_indicator,
+ .display = param->display,
+ .signal = param->signal,
+ .feature_indicate = param->feature_indicate,
+ .terminal_capability = param->terminal_capability,
+ .transit_delay = param->transit_delay,
+ .window_size = param->window_size,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ dect_cc_send_msg(dh, call, cc_connect_msg_desc, &msg.common,
+ CC_CONNECT, "CC-CONNECT");
+
+ dect_call_connect_uplane(dh, call);
+ return 0;
+}
+
+int dect_mncc_connect_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_connect_param *param)
+{
+ struct dect_cc_connect_ack_msg msg = {
+ .display = param->display,
+ .feature_indicate = param->feature_indicate,
+ //.iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ dect_call_connect_uplane(dh, call);
+ if (dect_cc_send_msg(dh, call, cc_connect_ack_msg_desc, &msg.common,
+ CC_CONNECT_ACK, "CC-CONNECT_ACK") < 0)
+ goto err1;
+
+ call->state = DECT_CC_ACTIVE;
+ return 0;
+
+err1:
+ dect_call_disconnect_uplane(dh, call);
+ return -1;
+}
+
+int dect_mncc_release_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param)
+{
+ struct dect_cc_release_msg msg = {
+ .release_reason = param->release_reason,
+ .facility = param->facility,
+ .display = param->display,
+ .feature_indicate = param->feature_indicate,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ dect_cc_send_msg(dh, call, cc_release_msg_desc, &msg.common,
+ CC_RELEASE, "CC-RELEASE");
+ call->state = DECT_CC_RELEASE_PENDING;
+ return 0;
+}
+
+int dect_mncc_release_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param)
+{
+ struct dect_cc_release_com_msg msg = {
+ .release_reason = param->release_reason,
+ .identity_type = param->identity_type,
+ .location_area = param->location_area,
+ .iwu_attributes = param->iwu_attributes,
+ //.facility = param->facility,
+ .display = param->display,
+ .feature_indicate = param->feature_indicate,
+ .network_parameter = param->network_parameter,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ dect_cc_send_msg(dh, call, cc_release_com_msg_desc, &msg.common,
+ CC_RELEASE_COM, "CC-RELEASE_COM");
+
+ dect_call_disconnect_uplane(dh, call);
+ dect_close_transaction(dh, &call->transaction);
+ dect_call_destroy(dh, call);
+ return 0;
+}
+
+int dect_mncc_facility_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_facility_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_info_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_info_param *param)
+{
+ struct dect_cc_info_msg msg = {
+ .location_area = param->location_area,
+ .nwk_assigned_identity = param->nwk_assigned_identity,
+ .facility = param->facility,
+// .progress_indicator = param->progress_indicator,
+ .display = param->display,
+ .keypad = param->keypad,
+ .signal = param->signal,
+ .feature_activate = param->feature_activate,
+ .feature_indicate = param->feature_indicate,
+ .network_parameter = param->network_parameter,
+ .called_party_number = param->called_party_number,
+ .called_party_subaddress = param->called_party_subaddress,
+ .calling_party_number = param->calling_party_number,
+ .calling_party_name = param->calling_party_name,
+ .sending_complete = param->sending_complete,
+ .iwu_to_iwu = param->iwu_to_iwu,
+ .iwu_packet = param->iwu_packet,
+ };
+
+ // FIXME FIXME FIXME FIXME
+ if (param->progress_indicator.list.next != NULL) {
+ init_list_head(&msg.progress_indicator.list);
+ dect_ie_list_move(&msg.progress_indicator,
+ (struct dect_ie_repeat_indicator *)&param->progress_indicator);
+ }
+
+ dect_cc_send_msg(dh, call, cc_info_msg_desc, &msg.common,
+ CC_INFO, "CC-INFO");
+ return 0;
+}
+
+int dect_mncc_modify_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_modify_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_modify_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_modify_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_hold_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_hold_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_retrieve_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_retrieve_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param)
+{
+ return 0;
+}
+
+int dect_mncc_iwu_info_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_iwu_info_param *param)
+{
+ return 0;
+}
+
+static void dect_mncc_alert_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_cc_alerting_msg *msg)
+{
+ struct dect_mncc_alert_param param = {
+ .facility = msg->facility,
+ .progress_indicator = msg->progress_indicator,
+ .display = msg->display,
+ .signal = msg->signal,
+ .feature_indicate = msg->feature_indicate,
+ .terminal_capability = msg->terminal_capability,
+ .transit_delay = msg->transit_delay,
+ .window_size = msg->window_size,
+ .iwu_to_iwu = msg->iwu_to_iwu,
+ .iwu_packet = msg->iwu_packet,
+ };
+
+ dh->ops->cc_ops->mncc_alert_ind(dh, call, &param);
+}
+
+static void dect_cc_rcv_alerting(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_alerting_msg msg;
+
+ dect_mbuf_dump(mb, "CC-ALERTING");
+ if (call->state != DECT_CC_CALL_PRESENT)
+ ;
+
+ if (dect_parse_sfmt_msg(dh, cc_alerting_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_mncc_alert_ind(dh, call, &msg);
+ dect_msg_free(dh, cc_alerting_msg_desc, &msg.common);
+ call->state = DECT_CC_CALL_RECEIVED;
+}
+
+static void dect_cc_rcv_call_proc(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_call_proc_msg msg;
+
+ dect_mbuf_dump(mb, "CC-CALL_PROC");
+ if (dect_parse_sfmt_msg(dh, cc_call_proc_msg_desc, &msg.common, mb) < 0)
+ return;
+}
+
+static void dect_mncc_connect_ind(struct dect_handle *dh, struct dect_call *call,
+ struct dect_cc_connect_msg *msg)
+{
+ struct dect_mncc_connect_param param = {
+ .facility = msg->facility,
+ .progress_indicator = msg->progress_indicator,
+ .display = msg->display,
+ .signal = msg->signal,
+ .feature_indicate = msg->feature_indicate,
+ .terminal_capability = msg->terminal_capability,
+ .transit_delay = msg->transit_delay,
+ .window_size = msg->window_size,
+ .iwu_to_iwu = msg->iwu_to_iwu,
+ .iwu_packet = msg->iwu_packet,
+ };
+
+ dh->ops->cc_ops->mncc_connect_ind(dh, call, &param);
+}
+
+static void dect_cc_rcv_connect(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_connect_msg msg;
+
+ if (call->state != DECT_CC_CALL_PRESENT &&
+ call->state != DECT_CC_CALL_RECEIVED)
+ ;
+
+ dect_mbuf_dump(mb, "CC-CONNECT");
+ if (dect_parse_sfmt_msg(dh, cc_connect_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ if (call->setup_timer != NULL) {
+ dect_stop_timer(dh, call->setup_timer);
+ dect_free(dh, call->setup_timer);
+ call->setup_timer = NULL;
+ }
+
+ dect_mncc_connect_ind(dh, call, &msg);
+ dect_msg_free(dh, cc_connect_msg_desc, &msg.common);
+}
+
+static void dect_cc_rcv_setup_ack(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_setup_ack_msg msg;
+
+ dect_mbuf_dump(mb, "CC-SETUP_ACK");
+ if (dect_parse_sfmt_msg(dh, cc_setup_ack_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_msg_free(dh, cc_setup_ack_msg_desc, &msg.common);
+}
+
+static void dect_cc_rcv_connect_ack(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_connect_ack_msg msg;
+
+ dect_mbuf_dump(mb, "CC-CONNECT_ACK");
+ if (dect_parse_sfmt_msg(dh, cc_connect_ack_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_msg_free(dh, cc_connect_ack_msg_desc, &msg.common);
+}
+
+static void dect_mncc_release_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_cc_release_msg *msg)
+{
+ struct dect_mncc_release_param param = {
+ .release_reason = msg->release_reason,
+ .facility = msg->facility,
+ .display = msg->display,
+ .feature_indicate = msg->feature_indicate,
+ .iwu_to_iwu = msg->iwu_to_iwu,
+ .iwu_packet = msg->iwu_packet,
+ };
+
+ dh->ops->cc_ops->mncc_release_ind(dh, call, &param);
+}
+
+static void dect_cc_rcv_release(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_release_msg msg;
+
+ dect_mbuf_dump(mb, "CC-RELEASE");
+ if (dect_parse_sfmt_msg(dh, cc_release_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_mncc_release_ind(dh, call, &msg);
+ dect_msg_free(dh, cc_release_msg_desc, &msg.common);
+}
+
+static void dect_mncc_release_cfm(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_cc_release_com_msg *msg)
+{
+ struct dect_mncc_release_param param = {
+ .release_reason = msg->release_reason,
+ .identity_type = msg->identity_type,
+ .location_area = msg->location_area,
+ .iwu_attributes = msg->iwu_attributes,
+ .facility = msg->facility,
+ .display = msg->display,
+ .feature_indicate = msg->feature_indicate,
+ .network_parameter = msg->network_parameter,
+ .iwu_to_iwu = msg->iwu_to_iwu,
+ .iwu_packet = msg->iwu_packet,
+
+ };
+
+ dh->ops->cc_ops->mncc_release_cfm(dh, call, &param);
+}
+
+static void dect_cc_rcv_release_com(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_release_com_msg msg;
+
+ dect_mbuf_dump(mb, "CC-RELEASE_COM");
+ if (dect_parse_sfmt_msg(dh, cc_release_com_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ if (call->state == DECT_CC_RELEASE_PENDING)
+ dect_mncc_release_cfm(dh, call, &msg);
+ else {
+ struct dect_mncc_release_param param = {
+ .release_reason = msg.release_reason,
+ .facility = msg.facility,
+ .iwu_to_iwu = msg.iwu_to_iwu,
+ .iwu_packet = msg.iwu_packet,
+ };
+ dh->ops->cc_ops->mncc_release_ind(dh, call, &param);
+ }
+
+ dect_msg_free(dh, cc_release_com_msg_desc, &msg.common);
+
+ if (call->lu_sap != NULL)
+ dect_call_disconnect_uplane(dh, call);
+ dect_close_transaction(dh, &call->transaction);
+ dect_call_destroy(dh, call);
+}
+
+static void dect_cc_rcv_iwu_info(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_iwu_info_msg msg;
+
+ dect_mbuf_dump(mb, "CC-IWU_INFO");
+ if (dect_parse_sfmt_msg(dh, cc_iwu_info_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_msg_free(dh, cc_iwu_info_msg_desc, &msg.common);
+}
+
+static void dect_cc_rcv_notify(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_notify_msg msg;
+
+ dect_mbuf_dump(mb, "CC-NOTIFY");
+ if (dect_parse_sfmt_msg(dh, cc_notify_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_msg_free(dh, cc_notify_msg_desc, &msg.common);
+}
+
+static void dect_mncc_info_ind(struct dect_handle *dh, struct dect_call *call,
+ struct dect_cc_info_msg *msg)
+{
+ struct dect_mncc_info_param param = {
+ .location_area = msg->location_area,
+ .nwk_assigned_identity = msg->nwk_assigned_identity,
+ .facility = msg->facility,
+ .progress_indicator = msg->progress_indicator,
+ .display = msg->display,
+ .keypad = msg->keypad,
+ .signal = msg->signal,
+ .feature_activate = msg->feature_activate,
+ .feature_indicate = msg->feature_indicate,
+ .network_parameter = msg->network_parameter,
+ .called_party_number = msg->called_party_number,
+ .called_party_subaddress = msg->called_party_subaddress,
+ .calling_party_number = msg->calling_party_number,
+ .calling_party_name = msg->calling_party_name,
+ .sending_complete = msg->sending_complete,
+ .iwu_to_iwu = msg->iwu_to_iwu,
+ .iwu_packet = msg->iwu_packet,
+ };
+
+ dh->ops->cc_ops->mncc_info_ind(dh, call, &param);
+}
+
+static void dect_cc_rcv_info(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct dect_cc_info_msg msg;
+
+ dect_mbuf_dump(mb, "CC-INFO");
+ if (call->state == DECT_CC_CALL_INITIATED ||
+ call->state == DECT_CC_CALL_PRESENT)
+ ;
+
+ if (dect_parse_sfmt_msg(dh, cc_info_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_mncc_info_ind(dh, call, &msg);
+ dect_msg_free(dh, cc_info_msg_desc, &msg.common);
+}
+
+static void dect_cc_rcv(struct dect_handle *dh, struct dect_transaction *ta,
+ struct dect_msg_buf *mb)
+{
+ struct dect_call *call = container_of(ta, struct dect_call, transaction);
+
+ cc_debug(call, "receive msg type %x", mb->type);
+ switch (mb->type) {
+ case CC_ALERTING:
+ return dect_cc_rcv_alerting(dh, call, mb);
+ case CC_CALL_PROC:
+ return dect_cc_rcv_call_proc(dh, call, mb);
+ case CC_CONNECT:
+ return dect_cc_rcv_connect(dh, call, mb);
+ case CC_SETUP_ACK:
+ return dect_cc_rcv_setup_ack(dh, call, mb);
+ case CC_CONNECT_ACK:
+ return dect_cc_rcv_connect_ack(dh, call, mb);
+ case CC_SERVICE_CHANGE:
+ case CC_SERVICE_ACCEPT:
+ case CC_SERVICE_REJECT:
+ case CC_RELEASE:
+ return dect_cc_rcv_release(dh, call, mb);
+ case CC_RELEASE_COM:
+ return dect_cc_rcv_release_com(dh, call, mb);
+ case CC_IWU_INFO:
+ return dect_cc_rcv_iwu_info(dh, call, mb);
+ case CC_NOTIFY:
+ return dect_cc_rcv_notify(dh, call, mb);
+ case CC_INFO:
+ return dect_cc_rcv_info(dh, call, mb);
+ }
+}
+
+static void dect_mncc_setup_ind(struct dect_handle *dh,
+ struct dect_call *call,
+ struct dect_cc_setup_msg *msg)
+{
+ struct dect_mncc_setup_param param = {
+ .basic_service = msg->basic_service,
+ .cipher_info = msg->cipher_info,
+ .display = msg->display,
+ .keypad = msg->keypad,
+ .signal = msg->signal,
+ .feature_activate = msg->feature_activate,
+ .feature_indicate = msg->feature_indicate,
+ .network_parameter = msg->network_parameter,
+ .terminal_capability = msg->terminal_capability,
+ .end_to_end_compatibility = msg->end_to_end_compatibility,
+ .rate_parameters = msg->rate_parameters,
+ .transit_delay = msg->transit_delay,
+ .window_size = msg->window_size,
+ .called_party_number = msg->called_party_number,
+ .called_party_subaddress = msg->called_party_subaddress,
+ .calling_party_number = msg->calling_party_number,
+ .calling_party_name = msg->calling_party_name,
+ .sending_complete = msg->sending_complete,
+ .iwu_to_iwu = msg->iwu_to_iwu,
+ .iwu_packet = msg->iwu_packet,
+ };
+
+ dect_ie_list_move(&param.iwu_attributes, &msg->iwu_attributes);
+ dect_ie_list_move(&param.facility, &msg->facility);
+ dect_ie_list_move(&param.progress_indicator, &msg->progress_indicator);
+
+ dh->ops->cc_ops->mncc_setup_ind(dh, call, &param);
+}
+
+static void dect_cc_rcv_setup(struct dect_handle *dh,
+ const struct dect_transaction *req,
+ struct dect_msg_buf *mb)
+{
+ struct dect_ie_connection_attributes *connection_attributes;
+ struct dect_ie_call_attributes *call_attributes;
+ struct dect_cc_setup_msg msg;
+ struct dect_call *call;
+
+ dect_mbuf_dump(mb, "CC-SETUP");
+ if (dect_parse_sfmt_msg(dh, cc_setup_msg_desc, &msg.common, mb) < 0)
+ return;
+
+ dect_foreach_ie(call_attributes, msg.call_attributes)
+ dect_debug("call attributes\n");
+
+ dect_foreach_ie(connection_attributes, msg.connection_attributes)
+ dect_debug("connection attributes\n");
+
+ call = dect_call_alloc(dh);
+ if (call == NULL)
+ goto out;
+ call->ft_id = dect_ie_hold(msg.fixed_identity);
+ call->pt_id = dect_ie_hold(msg.portable_identity);
+ call->state = DECT_CC_CALL_INITIATED;
+ dect_confirm_transaction(dh, &call->transaction, req);
+ cc_debug(call, "new call");
+
+ dect_mncc_setup_ind(dh, call, &msg);
+out:
+ dect_msg_free(dh, cc_setup_msg_desc, &msg.common);
+}
+
+static void dect_cc_open(struct dect_handle *dh,
+ const struct dect_transaction *req,
+ struct dect_msg_buf *mb)
+{
+ dect_debug("CC: unknown transaction msg type: %x\n", mb->type);
+
+ switch (mb->type) {
+ case CC_SETUP:
+ return dect_cc_rcv_setup(dh, req, mb);
+ case CC_RELEASE:
+ case CC_RELEASE_COM:
+ break;
+ default:
+ // send release-com
+ break;
+ }
+}
+
+static void dect_cc_shutdown(struct dect_handle *dh,
+ struct dect_transaction *ta)
+{
+ struct dect_call *call = container_of(ta, struct dect_call, transaction);
+
+ cc_debug(call, "shutdown");
+ dh->ops->cc_ops->mncc_reject_ind(dh, call, NULL);
+ dect_close_transaction(dh, &call->transaction);
+ dect_call_destroy(dh, call);
+}
+
+static const struct dect_nwk_protocol cc_protocol = {
+ .name = "Call Control",
+ .pd = DECT_S_PD_CC,
+ .max_transactions = 7,
+ .open = dect_cc_open,
+ .shutdown = dect_cc_shutdown,
+ .rcv = dect_cc_rcv,
+};
+
+static void __init dect_cc_init(void)
+{
+ dect_lce_register_protocol(&cc_protocol);
+}
diff --git a/src/ccitt-adpcm/README b/src/ccitt-adpcm/README
new file mode 100644
index 0000000..23b0e7d
--- /dev/null
+++ b/src/ccitt-adpcm/README
@@ -0,0 +1,94 @@
+The files in this directory comprise ANSI-C language reference implementations
+of the CCITT (International Telegraph and Telephone Consultative Committee)
+G.711, G.721 and G.723 voice compressions. They have been tested on Sun
+SPARCstations and passed 82 out of 84 test vectors published by CCITT
+(Dec. 20, 1988) for G.721 and G.723. [The two remaining test vectors,
+which the G.721 decoder implementation for u-law samples did not pass,
+may be in error because they are identical to two other vectors for G.723_40.]
+
+This source code is released by Sun Microsystems, Inc. to the public domain.
+Please give your acknowledgement in product literature if this code is used
+in your product implementation.
+
+Sun Microsystems supports some CCITT audio formats in Solaris 2.0 system
+software. However, Sun's implementations have been optimized for higher
+performance on SPARCstations.
+
+
+The source files for CCITT conversion routines in this directory are:
+
+ g72x.h header file for g721.c, g723_24.c and g723_40.c
+ g711.c CCITT G.711 u-law and A-law compression
+ g72x.c common denominator of G.721 and G.723 ADPCM codes
+ g721.c CCITT G.721 32Kbps ADPCM coder (with g72x.c)
+ g723_24.c CCITT G.723 24Kbps ADPCM coder (with g72x.c)
+ g723_40.c CCITT G.723 40Kbps ADPCM coder (with g72x.c)
+
+
+Simple conversions between u-law, A-law, and 16-bit linear PCM are invoked
+as follows:
+
+ unsigned char ucode, acode;
+ short pcm_val;
+
+ ucode = linear2ulaw(pcm_val);
+ ucode = alaw2ulaw(acode);
+
+ acode = linear2alaw(pcm_val);
+ acode = ulaw2alaw(ucode);
+
+ pcm_val = ulaw2linear(ucode);
+ pcm_val = alaw2linear(acode);
+
+
+The other CCITT compression routines are invoked as follows:
+
+ #include "g72x.h"
+
+ struct g72x_state state;
+ int sample, code;
+
+ g72x_init_state(&state);
+ code = {g721,g723_24,g723_40}_encoder(sample, coding, &state);
+ sample = {g721,g723_24,g723_40}_decoder(code, coding, &state);
+
+where
+ coding = AUDIO_ENCODING_ULAW for 8-bit u-law samples
+ AUDIO_ENCODING_ALAW for 8-bit A-law samples
+ AUDIO_ENCODING_LINEAR for 16-bit linear PCM samples
+
+
+
+This directory also includes the following sample programs:
+
+ encode.c CCITT ADPCM encoder
+ decode.c CCITT ADPCM decoder
+ Makefile makefile for the sample programs
+
+
+The sample programs contain examples of how to call the various compression
+routines and pack/unpack the bits. The sample programs read byte streams from
+stdin and write to stdout. The input/output data is raw data (no file header
+or other identifying information is embedded). The sample programs are
+invoked as follows:
+
+ encode [-3|4|5] [-a|u|l] <infile >outfile
+ decode [-3|4|5] [-a|u|l] <infile >outfile
+where:
+ -3 encode to (decode from) G.723 24kbps (3-bit) data
+ -4 encode to (decode from) G.721 32kbps (4-bit) data [the default]
+ -5 encode to (decode from) G.723 40kbps (5-bit) data
+ -a encode from (decode to) A-law data
+ -u encode from (decode to) u-law data [the default]
+ -l encode from (decode to) 16-bit linear data
+
+Examples:
+ # Read 16-bit linear and output G.721
+ encode -4 -l <pcmfile >g721file
+
+ # Read 40Kbps G.723 and output A-law
+ decode -5 -a <g723file >alawfile
+
+ # Compress and then decompress u-law data using 24Kbps G.723
+ encode -3 <ulawin | deoced -3 >ulawout
+
diff --git a/src/ccitt-adpcm/decode.c b/src/ccitt-adpcm/decode.c
new file mode 100644
index 0000000..cf8c739
--- /dev/null
+++ b/src/ccitt-adpcm/decode.c
@@ -0,0 +1,113 @@
+/*
+ * decode.c
+ *
+ * CCITT ADPCM decoder
+ *
+ * Usage : decode [-3|4|5] [-a|u|l] < infile > outfile
+ */
+#include <stdio.h>
+#include "g72x.h"
+
+
+/*
+ * Unpack input codes and pass them back as bytes.
+ * Returns 1 if there is residual input, returns -1 if eof, else returns 0.
+ */
+int
+unpack_input(
+ unsigned char *code,
+ int bits)
+{
+ static unsigned int in_buffer = 0;
+ static int in_bits = 0;
+ unsigned char in_byte;
+
+ if (in_bits < bits) {
+ if (fread(&in_byte, sizeof (char), 1, stdin) != 1) {
+ *code = 0;
+ return (-1);
+ }
+ in_buffer |= (in_byte << in_bits);
+ in_bits += 8;
+ }
+ *code = in_buffer & ((1 << bits) - 1);
+ in_buffer >>= bits;
+ in_bits -= bits;
+ return (in_bits > 0);
+}
+
+
+main(
+ int argc,
+ char **argv)
+{
+ short sample;
+ unsigned char code;
+ int n;
+ struct g72x_state state;
+ int out_coding;
+ int out_size;
+ int (*dec_routine)();
+ int dec_bits;
+
+ g72x_init_state(&state);
+ out_coding = AUDIO_ENCODING_ULAW;
+ out_size = sizeof (char);
+ dec_routine = g721_decoder;
+ dec_bits = 4;
+
+ /* Process encoding argument, if any */
+ while ((argc > 1) && (argv[1][0] == '-')) {
+ switch (argv[1][1]) {
+ case '3':
+ dec_routine = g723_24_decoder;
+ dec_bits = 3;
+ break;
+ case '4':
+ dec_routine = g721_decoder;
+ dec_bits = 4;
+ break;
+ case '5':
+ dec_routine = g723_40_decoder;
+ dec_bits = 5;
+ break;
+ case 'u':
+ out_coding = AUDIO_ENCODING_ULAW;
+ out_size = sizeof (char);
+ break;
+ case 'a':
+ out_coding = AUDIO_ENCODING_ALAW;
+ out_size = sizeof (char);
+ break;
+ case 'l':
+ out_coding = AUDIO_ENCODING_LINEAR;
+ out_size = sizeof (short);
+ break;
+ default:
+fprintf(stderr, "CCITT ADPCM Decoder -- usage:\n");
+fprintf(stderr, "\tdecode [-3|4|5] [-a|u|l] < infile > outfile\n");
+fprintf(stderr, "where:\n");
+fprintf(stderr, "\t-3\tProcess G.723 24kbps (3-bit) input data\n");
+fprintf(stderr, "\t-4\tProcess G.721 32kbps (4-bit) input data [default]\n");
+fprintf(stderr, "\t-5\tProcess G.723 40kbps (5-bit) input data\n");
+fprintf(stderr, "\t-a\tGenerate 8-bit A-law data\n");
+fprintf(stderr, "\t-u\tGenerate 8-bit u-law data [default]\n");
+fprintf(stderr, "\t-l\tGenerate 16-bit linear PCM data\n");
+ exit(1);
+ }
+ argc--;
+ argv++;
+ }
+
+ /* Read and unpack input codes and process them */
+ while (unpack_input(&code, dec_bits) >= 0) {
+ sample = (*dec_routine)(code, out_coding, &state);
+ if (out_size == 2) {
+ fwrite(&sample, out_size, 1, stdout);
+ } else {
+ code = (unsigned char)sample;
+ fwrite(&code, out_size, 1, stdout);
+ }
+ }
+ fclose(stdout);
+}
diff --git a/src/ccitt-adpcm/encode.c b/src/ccitt-adpcm/encode.c
new file mode 100644
index 0000000..571fbe8
--- /dev/null
+++ b/src/ccitt-adpcm/encode.c
@@ -0,0 +1,119 @@
+/*
+ * encode.c
+ *
+ * CCITT ADPCM encoder
+ *
+ * Usage : encode [-3|4|5] [-a|u|l] < infile > outfile
+ */
+#include <stdio.h>
+#include "g72x.h"
+
+
+/*
+ * Pack output codes into bytes and write them to stdout.
+ * Returns 1 if there is residual output, else returns 0.
+ */
+int
+pack_output(
+ unsigned code,
+ int bits)
+{
+ static unsigned int out_buffer = 0;
+ static int out_bits = 0;
+ unsigned char out_byte;
+
+ out_buffer |= (code << out_bits);
+ out_bits += bits;
+ if (out_bits >= 8) {
+ out_byte = out_buffer & 0xff;
+ out_bits -= 8;
+ out_buffer >>= 8;
+ fwrite(&out_byte, sizeof (char), 1, stdout);
+ }
+ return (out_bits > 0);
+}
+
+
+main(
+ int argc,
+ char **argv)
+{
+ struct g72x_state state;
+ unsigned char sample_char;
+ short sample_short;
+ unsigned char code;
+ int resid;
+ int in_coding;
+ int in_size;
+ unsigned *in_buf;
+ int (*enc_routine)();
+ int enc_bits;
+
+ g72x_init_state(&state);
+
+ /* Set defaults to u-law input, G.721 output */
+ in_coding = AUDIO_ENCODING_ULAW;
+ in_size = sizeof (char);
+ in_buf = (unsigned *)&sample_char;
+ enc_routine = g721_encoder;
+ enc_bits = 4;
+
+ /* Process encoding argument, if any */
+ while ((argc > 1) && (argv[1][0] == '-')) {
+ switch (argv[1][1]) {
+ case '3':
+ enc_routine = g723_24_encoder;
+ enc_bits = 3;
+ break;
+ case '4':
+ enc_routine = g721_encoder;
+ enc_bits = 4;
+ break;
+ case '5':
+ enc_routine = g723_40_encoder;
+ enc_bits = 5;
+ break;
+ case 'u':
+ in_coding = AUDIO_ENCODING_ULAW;
+ in_size = sizeof (char);
+ in_buf = (unsigned *)&sample_char;
+ break;
+ case 'a':
+ in_coding = AUDIO_ENCODING_ALAW;
+ in_size = sizeof (char);
+ in_buf = (unsigned *)&sample_char;
+ break;
+ case 'l':
+ in_coding = AUDIO_ENCODING_LINEAR;
+ in_size = sizeof (short);
+ in_buf = (unsigned *)&sample_short;
+ break;
+ default:
+fprintf(stderr, "CCITT ADPCM Encoder -- usage:\n");
+fprintf(stderr, "\tencode [-3|4|5] [-a|u|l] < infile > outfile\n");
+fprintf(stderr, "where:\n");
+fprintf(stderr, "\t-3\tGenerate G.723 24kbps (3-bit) data\n");
+fprintf(stderr, "\t-4\tGenerate G.721 32kbps (4-bit) data [default]\n");
+fprintf(stderr, "\t-5\tGenerate G.723 40kbps (5-bit) data\n");
+fprintf(stderr, "\t-a\tProcess 8-bit A-law input data\n");
+fprintf(stderr, "\t-u\tProcess 8-bit u-law input data [default]\n");
+fprintf(stderr, "\t-l\tProcess 16-bit linear PCM input data\n");
+ exit(1);
+ }
+ argc--;
+ argv++;
+ }
+
+ /* Read input file and process */
+ while (fread(in_buf, in_size, 1, stdin) == 1) {
+ code = (*enc_routine)(in_size == 2 ? sample_short : sample_char,
+ in_coding, &state);
+ resid = pack_output(code, enc_bits);
+ }
+
+ /* Write zero codes until all residual codes are written out */
+ while (resid) {
+ resid = pack_output(0, enc_bits);
+ }
+ fclose(stdout);
+}
diff --git a/src/ccitt-adpcm/g711.c b/src/ccitt-adpcm/g711.c
new file mode 100644
index 0000000..f9eab50
--- /dev/null
+++ b/src/ccitt-adpcm/g711.c
@@ -0,0 +1,285 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include "g72x.h"
+
+/*
+ * g711.c
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
+#define QUANT_MASK (0xf) /* Quantization field mask. */
+#define NSEGS (8) /* Number of A-law segments. */
+#define SEG_SHIFT (4) /* Left shift for segment number. */
+#define SEG_MASK (0x70) /* Segment field mask. */
+
+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
+
+/* copy from CCITT G.711 specifications */
+unsigned char _u2a[128] = { /* u- to A-law conversions */
+ 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 27, 29, 31, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44,
+ 46, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128};
+
+unsigned char _a2u[128] = { /* A- to u-law conversions */
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 48, 49, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127};
+
+static int
+search(
+ int val,
+ short *table,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (val <= *table++)
+ return (i);
+ }
+ return (size);
+}
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+linear2alaw(
+ int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char aval;
+
+ if (pcm_val >= 0) {
+ mask = 0xD5; /* sign (7th) bit = 1 */
+ } else {
+ mask = 0x55; /* sign bit = 0 */
+ pcm_val = -pcm_val - 8;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /* Combine the sign, segment, and quantization bits. */
+
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ aval = seg << SEG_SHIFT;
+ if (seg < 2)
+ aval |= (pcm_val >> 4) & QUANT_MASK;
+ else
+ aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
+ return (aval ^ mask);
+ }
+}
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+int
+alaw2linear(
+ unsigned char a_val)
+{
+ int t;
+ int seg;
+
+ a_val ^= 0x55;
+
+ t = (a_val & QUANT_MASK) << 4;
+ seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+ switch (seg) {
+ case 0:
+ t += 8;
+ break;
+ case 1:
+ t += 0x108;
+ break;
+ default:
+ t += 0x108;
+ t <<= seg - 1;
+ }
+ return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+#define BIAS (0x84) /* Bias for linear code. */
+
+/*
+ * linear2ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+linear2ulaw(
+ int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char uval;
+
+ /* Get the sign and the magnitude of the value. */
+ if (pcm_val < 0) {
+ pcm_val = BIAS - pcm_val;
+ mask = 0x7F;
+ } else {
+ pcm_val += BIAS;
+ mask = 0xFF;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /*
+ * Combine the sign, segment, quantization bits;
+ * and complement the code word.
+ */
+ if (seg >= 8) /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ else {
+ uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
+ return (uval ^ mask);
+ }
+
+}
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+int
+ulaw2linear(
+ unsigned char u_val)
+{
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ u_val = ~u_val;
+
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = ((u_val & QUANT_MASK) << 3) + BIAS;
+ t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+
+ return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+/* A-law to u-law conversion */
+unsigned char
+alaw2ulaw(
+ unsigned char aval)
+{
+ aval &= 0xff;
+ return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+ (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/* u-law to A-law conversion */
+unsigned char
+ulaw2alaw(
+ unsigned char uval)
+{
+ uval &= 0xff;
+ return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+ (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
diff --git a/src/ccitt-adpcm/g721.c b/src/ccitt-adpcm/g721.c
new file mode 100644
index 0000000..445f177
--- /dev/null
+++ b/src/ccitt-adpcm/g721.c
@@ -0,0 +1,173 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g721.c
+ *
+ * Description:
+ *
+ * g721_encoder(), g721_decoder()
+ *
+ * These routines comprise an implementation of the CCITT G.721 ADPCM
+ * coding algorithm. Essentially, this implementation is identical to
+ * the bit level description except for a few deviations which
+ * take advantage of work station attributes, such as hardware 2's
+ * complement arithmetic and large memory. Specifically, certain time
+ * consuming operations such as multiplications are replaced
+ * with lookup tables and software 2's complement operations are
+ * replaced with hardware 2's complement.
+ *
+ * The deviation from the bit level specification (lookup tables)
+ * preserves the bit level performance specifications.
+ *
+ * As outlined in the G.721 Recommendation, the algorithm is broken
+ * down into modules. Each section of code below is preceded by
+ * the name of the module which it is implementing.
+ *
+ */
+#include "g72x.h"
+
+static short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400};
+/*
+ * Maps G.721 code word to reconstructed scale factor normalized log
+ * magnitude values.
+ */
+static short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425,
+ 425, 373, 323, 273, 213, 135, 4, -2048};
+
+/* Maps G.721 code word to log of scale factor multiplier. */
+static short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122,
+ 1122, 355, 198, 112, 64, 41, 18, -12};
+/*
+ * Maps G.721 code words to a set of values whose long and short
+ * term averages are computed and then compared to give an indication
+ * how stationary (steady state) the signal is.
+ */
+static short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00,
+ 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0};
+
+/*
+ * g721_encoder()
+ *
+ * Encodes the input vale of linear PCM, A-law or u-law data sl and returns
+ * the resulting code. -1 is returned for unknown input coding value.
+ */
+int
+g721_encoder(
+ int sl,
+ int in_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, se, sez; /* ACCUM */
+ short d; /* SUBTA */
+ short sr; /* ADDB */
+ short y; /* MIX */
+ short dqsez; /* ADDC */
+ short dq, i;
+
+ switch (in_coding) { /* linearize input sample to 14-bit PCM */
+ case AUDIO_ENCODING_ALAW:
+ sl = alaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ sl = ulaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ sl >>= 2; /* 14-bit dynamic range */
+ break;
+ default:
+ return (-1);
+ }
+
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */
+
+ d = sl - se; /* estimation difference */
+
+ /* quantize the prediction difference */
+ y = step_size(state_ptr); /* quantizer step size */
+ i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */
+
+ dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */
+
+ sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */
+
+ dqsez = sr + sez - se; /* pole prediction diff. */
+
+ update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
+
+ return (i);
+}
+
+/*
+ * g721_decoder()
+ *
+ * Description:
+ *
+ * Decodes a 4-bit code of G.721 encoded data of i and
+ * returns the resulting linear PCM, A-law or u-law value.
+ * return -1 for unknown out_coding value.
+ */
+int
+g721_decoder(
+ int i,
+ int out_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, sei, sez, se; /* ACCUM */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dq;
+ short dqsez;
+
+ i &= 0x0f; /* mask to get proper bits */
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ y = step_size(state_ptr); /* dynamic quantizer step size */
+
+ dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */
+
+ sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */
+
+ dqsez = sr - se + sez; /* pole prediction diff. */
+
+ update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
+
+ switch (out_coding) {
+ case AUDIO_ENCODING_ALAW:
+ return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721));
+ case AUDIO_ENCODING_ULAW:
+ return (tandem_adjust_ulaw(sr, se, y, i, 8, qtab_721));
+ case AUDIO_ENCODING_LINEAR:
+ return (sr << 2); /* sr was 14-bit dynamic range */
+ default:
+ return (-1);
+ }
+}
diff --git a/src/ccitt-adpcm/g723_24.c b/src/ccitt-adpcm/g723_24.c
new file mode 100644
index 0000000..452f4da
--- /dev/null
+++ b/src/ccitt-adpcm/g723_24.c
@@ -0,0 +1,158 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g723_24.c
+ *
+ * Description:
+ *
+ * g723_24_encoder(), g723_24_decoder()
+ *
+ * These routines comprise an implementation of the CCITT G.723 24 Kbps
+ * ADPCM coding algorithm. Essentially, this implementation is identical to
+ * the bit level description except for a few deviations which take advantage
+ * of workstation attributes, such as hardware 2's complement arithmetic.
+ *
+ */
+#include "g72x.h"
+
+/*
+ * Maps G.723_24 code word to reconstructed scale factor normalized log
+ * magnitude values.
+ */
+static short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048};
+
+/* Maps G.723_24 code word to log of scale factor multiplier. */
+static short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128};
+
+/*
+ * Maps G.723_24 code words to a set of values whose long and short
+ * term averages are computed and then compared to give an indication
+ * how stationary (steady state) the signal is.
+ */
+static short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0};
+
+static short qtab_723_24[3] = {8, 218, 331};
+
+/*
+ * g723_24_encoder()
+ *
+ * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code.
+ * Returns -1 if invalid input coding value.
+ */
+int
+g723_24_encoder(
+ int sl,
+ int in_coding,
+ struct g72x_state *state_ptr)
+{
+ short sei, sezi, se, sez; /* ACCUM */
+ short d; /* SUBTA */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dqsez; /* ADDC */
+ short dq, i;
+
+ switch (in_coding) { /* linearize input sample to 14-bit PCM */
+ case AUDIO_ENCODING_ALAW:
+ sl = alaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ sl = ulaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ sl >>= 2; /* sl of 14-bit dynamic range */
+ break;
+ default:
+ return (-1);
+ }
+
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ d = sl - se; /* d = estimation diff. */
+
+ /* quantize prediction difference d */
+ y = step_size(state_ptr); /* quantizer step size */
+ i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */
+ dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */
+
+ sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */
+
+ dqsez = sr + sez - se; /* pole prediction diff. */
+
+ update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ return (i);
+}
+
+/*
+ * g723_24_decoder()
+ *
+ * Decodes a 3-bit CCITT G.723_24 ADPCM code and returns
+ * the resulting 16-bit linear PCM, A-law or u-law sample value.
+ * -1 is returned if the output coding is unknown.
+ */
+int
+g723_24_decoder(
+ int i,
+ int out_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, sei, sez, se; /* ACCUM */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dq;
+ short dqsez;
+
+ i &= 0x07; /* mask to get proper bits */
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ y = step_size(state_ptr); /* adaptive quantizer step size */
+ dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */
+
+ sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */
+
+ dqsez = sr - se + sez; /* pole prediction diff. */
+
+ update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ switch (out_coding) {
+ case AUDIO_ENCODING_ALAW:
+ return (tandem_adjust_alaw(sr, se, y, i, 4, qtab_723_24));
+ case AUDIO_ENCODING_ULAW:
+ return (tandem_adjust_ulaw(sr, se, y, i, 4, qtab_723_24));
+ case AUDIO_ENCODING_LINEAR:
+ return (sr << 2); /* sr was of 14-bit dynamic range */
+ default:
+ return (-1);
+ }
+}
diff --git a/src/ccitt-adpcm/g723_40.c b/src/ccitt-adpcm/g723_40.c
new file mode 100644
index 0000000..4858baf
--- /dev/null
+++ b/src/ccitt-adpcm/g723_40.c
@@ -0,0 +1,178 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g723_40.c
+ *
+ * Description:
+ *
+ * g723_40_encoder(), g723_40_decoder()
+ *
+ * These routines comprise an implementation of the CCITT G.723 40Kbps
+ * ADPCM coding algorithm. Essentially, this implementation is identical to
+ * the bit level description except for a few deviations which
+ * take advantage of workstation attributes, such as hardware 2's
+ * complement arithmetic.
+ *
+ * The deviation from the bit level specification (lookup tables),
+ * preserves the bit level performance specifications.
+ *
+ * As outlined in the G.723 Recommendation, the algorithm is broken
+ * down into modules. Each section of code below is preceded by
+ * the name of the module which it is implementing.
+ *
+ */
+#include "g72x.h"
+
+/*
+ * Maps G.723_40 code word to ructeconstructed scale factor normalized log
+ * magnitude values.
+ */
+static short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318,
+ 358, 395, 429, 459, 488, 514, 539, 566,
+ 566, 539, 514, 488, 459, 429, 395, 358,
+ 318, 274, 224, 169, 104, 28, -66, -2048};
+
+/* Maps G.723_40 code word to log of scale factor multiplier. */
+static short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200,
+ 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272,
+ 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512,
+ 3200, 1856, 1312, 1280, 1248, 768, 448, 448};
+
+/*
+ * Maps G.723_40 code words to a set of values whose long and short
+ * term averages are computed and then compared to give an indication
+ * how stationary (steady state) the signal is.
+ */
+static short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200,
+ 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00,
+ 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200,
+ 0x200, 0x200, 0x200, 0, 0, 0, 0, 0};
+
+static short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339,
+ 378, 413, 445, 475, 502, 528, 553};
+
+/*
+ * g723_40_encoder()
+ *
+ * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens
+ * the resulting 5-bit CCITT G.723 40Kbps code.
+ * Returns -1 if the input coding value is invalid.
+ */
+int
+g723_40_encoder(
+ int sl,
+ int in_coding,
+ struct g72x_state *state_ptr)
+{
+ short sei, sezi, se, sez; /* ACCUM */
+ short d; /* SUBTA */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dqsez; /* ADDC */
+ short dq, i;
+
+ switch (in_coding) { /* linearize input sample to 14-bit PCM */
+ case AUDIO_ENCODING_ALAW:
+ sl = alaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_ULAW:
+ sl = ulaw2linear(sl) >> 2;
+ break;
+ case AUDIO_ENCODING_LINEAR:
+ sl >>= 2; /* sl of 14-bit dynamic range */
+ break;
+ default:
+ return (-1);
+ }
+
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ d = sl - se; /* d = estimation difference */
+
+ /* quantize prediction difference */
+ y = step_size(state_ptr); /* adaptive quantizer step size */
+ i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */
+
+ dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */
+
+ sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */
+
+ dqsez = sr + sez - se; /* dqsez = pole prediction diff. */
+
+ update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ return (i);
+}
+
+/*
+ * g723_40_decoder()
+ *
+ * Decodes a 5-bit CCITT G.723 40Kbps code and returns
+ * the resulting 16-bit linear PCM, A-law or u-law sample value.
+ * -1 is returned if the output coding is unknown.
+ */
+int
+g723_40_decoder(
+ int i,
+ int out_coding,
+ struct g72x_state *state_ptr)
+{
+ short sezi, sei, sez, se; /* ACCUM */
+ short y; /* MIX */
+ short sr; /* ADDB */
+ short dq;
+ short dqsez;
+
+ i &= 0x1f; /* mask to get proper bits */
+ sezi = predictor_zero(state_ptr);
+ sez = sezi >> 1;
+ sei = sezi + predictor_pole(state_ptr);
+ se = sei >> 1; /* se = estimated signal */
+
+ y = step_size(state_ptr); /* adaptive quantizer step size */
+ dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */
+
+ sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */
+
+ dqsez = sr - se + sez; /* pole prediction diff. */
+
+ update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr);
+
+ switch (out_coding) {
+ case AUDIO_ENCODING_ALAW:
+ return (tandem_adjust_alaw(sr, se, y, i, 0x10, qtab_723_40));
+ case AUDIO_ENCODING_ULAW:
+ return (tandem_adjust_ulaw(sr, se, y, i, 0x10, qtab_723_40));
+ case AUDIO_ENCODING_LINEAR:
+ return (sr << 2); /* sr was of 14-bit dynamic range */
+ default:
+ return (-1);
+ }
+}
diff --git a/src/ccitt-adpcm/g72x.c b/src/ccitt-adpcm/g72x.c
new file mode 100644
index 0000000..ca17c35
--- /dev/null
+++ b/src/ccitt-adpcm/g72x.c
@@ -0,0 +1,565 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g72x.c
+ *
+ * Common routines for G.721 and G.723 conversions.
+ */
+
+#include <stdlib.h>
+#include "g72x.h"
+
+static short power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
+ 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000};
+
+/*
+ * quan()
+ *
+ * quantizes the input val against the table of size short integers.
+ * It returns i if table[i - 1] <= val < table[i].
+ *
+ * Using linear search for simple coding.
+ */
+static int
+quan(
+ int val,
+ short *table,
+ int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (val < *table++)
+ break;
+ return (i);
+}
+
+/*
+ * fmult()
+ *
+ * returns the integer product of the 14-bit integer "an" and
+ * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
+ */
+static int
+fmult(
+ int an,
+ int srn)
+{
+ short anmag, anexp, anmant;
+ short wanexp, wanmant;
+ short retval;
+
+ anmag = (an > 0) ? an : ((-an) & 0x1FFF);
+ anexp = quan(anmag, power2, 15) - 6;
+ anmant = (anmag == 0) ? 32 :
+ (anexp >= 0) ? anmag >> anexp : anmag << -anexp;
+ wanexp = anexp + ((srn >> 6) & 0xF) - 13;
+
+ wanmant = (anmant * (srn & 077) + 0x30) >> 4;
+ retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
+ (wanmant >> -wanexp);
+
+ return (((an ^ srn) < 0) ? -retval : retval);
+}
+
+/*
+ * g72x_init_state()
+ *
+ * This routine initializes and/or resets the g72x_state structure
+ * pointed to by 'state_ptr'.
+ * All the initial state values are specified in the CCITT G.721 document.
+ */
+void
+g72x_init_state(
+ struct g72x_state *state_ptr)
+{
+ int cnta;
+
+ state_ptr->yl = 34816;
+ state_ptr->yu = 544;
+ state_ptr->dms = 0;
+ state_ptr->dml = 0;
+ state_ptr->ap = 0;
+ for (cnta = 0; cnta < 2; cnta++) {
+ state_ptr->a[cnta] = 0;
+ state_ptr->pk[cnta] = 0;
+ state_ptr->sr[cnta] = 32;
+ }
+ for (cnta = 0; cnta < 6; cnta++) {
+ state_ptr->b[cnta] = 0;
+ state_ptr->dq[cnta] = 32;
+ }
+ state_ptr->td = 0;
+}
+
+/*
+ * predictor_zero()
+ *
+ * computes the estimated signal from 6-zero predictor.
+ *
+ */
+int
+predictor_zero(
+ struct g72x_state *state_ptr)
+{
+ int i;
+ int sezi;
+
+ sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
+ for (i = 1; i < 6; i++) /* ACCUM */
+ sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
+ return (sezi);
+}
+/*
+ * predictor_pole()
+ *
+ * computes the estimated signal from 2-pole predictor.
+ *
+ */
+int
+predictor_pole(
+ struct g72x_state *state_ptr)
+{
+ return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
+ fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
+}
+/*
+ * step_size()
+ *
+ * computes the quantization step size of the adaptive quantizer.
+ *
+ */
+int
+step_size(
+ struct g72x_state *state_ptr)
+{
+ int y;
+ int dif;
+ int al;
+
+ if (state_ptr->ap >= 256)
+ return (state_ptr->yu);
+ else {
+ y = state_ptr->yl >> 6;
+ dif = state_ptr->yu - y;
+ al = state_ptr->ap >> 2;
+ if (dif > 0)
+ y += (dif * al) >> 6;
+ else if (dif < 0)
+ y += (dif * al + 0x3F) >> 6;
+ return (y);
+ }
+}
+
+/*
+ * quantize()
+ *
+ * Given a raw sample, 'd', of the difference signal and a
+ * quantization step size scale factor, 'y', this routine returns the
+ * ADPCM codeword to which that sample gets quantized. The step
+ * size scale factor division operation is done in the log base 2 domain
+ * as a subtraction.
+ */
+int
+quantize(
+ int d, /* Raw difference signal sample */
+ int y, /* Step size multiplier */
+ short *table, /* quantization table */
+ int size) /* table size of short integers */
+{
+ short dqm; /* Magnitude of 'd' */
+ short exp; /* Integer part of base 2 log of 'd' */
+ short mant; /* Fractional part of base 2 log */
+ short dl; /* Log of magnitude of 'd' */
+ short dln; /* Step size scale factor normalized log */
+ int i;
+
+ /*
+ * LOG
+ *
+ * Compute base 2 log of 'd', and store in 'dl'.
+ */
+ dqm = abs(d);
+ exp = quan(dqm >> 1, power2, 15);
+ mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */
+ dl = (exp << 7) + mant;
+
+ /*
+ * SUBTB
+ *
+ * "Divide" by step size multiplier.
+ */
+ dln = dl - (y >> 2);
+
+ /*
+ * QUAN
+ *
+ * Obtain codword i for 'd'.
+ */
+ i = quan(dln, table, size);
+ if (d < 0) /* take 1's complement of i */
+ return ((size << 1) + 1 - i);
+ else if (i == 0) /* take 1's complement of 0 */
+ return ((size << 1) + 1); /* new in 1988 */
+ else
+ return (i);
+}
+/*
+ * reconstruct()
+ *
+ * Returns reconstructed difference signal 'dq' obtained from
+ * codeword 'i' and quantization step size scale factor 'y'.
+ * Multiplication is performed in log base 2 domain as addition.
+ */
+int
+reconstruct(
+ int sign, /* 0 for non-negative value */
+ int dqln, /* G.72x codeword */
+ int y) /* Step size multiplier */
+{
+ short dql; /* Log of 'dq' magnitude */
+ short dex; /* Integer part of log */
+ short dqt;
+ short dq; /* Reconstructed difference signal sample */
+
+ dql = dqln + (y >> 2); /* ADDA */
+
+ if (dql < 0) {
+ return ((sign) ? -0x8000 : 0);
+ } else { /* ANTILOG */
+ dex = (dql >> 7) & 15;
+ dqt = 128 + (dql & 127);
+ dq = (dqt << 7) >> (14 - dex);
+ return ((sign) ? (dq - 0x8000) : dq);
+ }
+}
+
+
+/*
+ * update()
+ *
+ * updates the state variables for each output code
+ */
+void
+update(
+ int code_size, /* distinguish 723_40 with others */
+ int y, /* quantizer step size */
+ int wi, /* scale factor multiplier */
+ int fi, /* for long/short term energies */
+ int dq, /* quantized prediction difference */
+ int sr, /* reconstructed signal */
+ int dqsez, /* difference from 2-pole predictor */
+ struct g72x_state *state_ptr) /* coder state pointer */
+{
+ int cnt;
+ short mag, exp; /* Adaptive predictor, FLOAT A */
+ short a2p = 0; /* LIMC */
+ short a1ul; /* UPA1 */
+ short pks1; /* UPA2 */
+ short fa1;
+ char tr; /* tone/transition detector */
+ short ylint, thr2, dqthr;
+ short ylfrac, thr1;
+ short pk0;
+
+ pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
+
+ mag = dq & 0x7FFF; /* prediction difference magnitude */
+ /* TRANS */
+ ylint = state_ptr->yl >> 15; /* exponent part of yl */
+ ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
+ thr1 = (32 + ylfrac) << ylint; /* threshold */
+ thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
+ dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
+ if (state_ptr->td == 0) /* signal supposed voice */
+ tr = 0;
+ else if (mag <= dqthr) /* supposed data, but small mag */
+ tr = 0; /* treated as voice */
+ else /* signal is data (modem) */
+ tr = 1;
+
+ /*
+ * Quantizer scale factor adaptation.
+ */
+
+ /* FUNCTW & FILTD & DELAY */
+ /* update non-steady state step size multiplier */
+ state_ptr->yu = y + ((wi - y) >> 5);
+
+ /* LIMB */
+ if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
+ state_ptr->yu = 544;
+ else if (state_ptr->yu > 5120)
+ state_ptr->yu = 5120;
+
+ /* FILTE & DELAY */
+ /* update steady state step size multiplier */
+ state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
+
+ /*
+ * Adaptive predictor coefficients.
+ */
+ if (tr == 1) { /* reset a's and b's for modem signal */
+ state_ptr->a[0] = 0;
+ state_ptr->a[1] = 0;
+ state_ptr->b[0] = 0;
+ state_ptr->b[1] = 0;
+ state_ptr->b[2] = 0;
+ state_ptr->b[3] = 0;
+ state_ptr->b[4] = 0;
+ state_ptr->b[5] = 0;
+ } else { /* update a's and b's */
+ pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
+
+ /* update predictor pole a[1] */
+ a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
+ if (dqsez != 0) {
+ fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
+ if (fa1 < -8191) /* a2p = function of fa1 */
+ a2p -= 0x100;
+ else if (fa1 > 8191)
+ a2p += 0xFF;
+ else
+ a2p += fa1 >> 5;
+
+ if (pk0 ^ state_ptr->pk[1])
+ /* LIMC */
+ if (a2p <= -12160)
+ a2p = -12288;
+ else if (a2p >= 12416)
+ a2p = 12288;
+ else
+ a2p -= 0x80;
+ else if (a2p <= -12416)
+ a2p = -12288;
+ else if (a2p >= 12160)
+ a2p = 12288;
+ else
+ a2p += 0x80;
+ }
+
+ /* TRIGB & DELAY */
+ state_ptr->a[1] = a2p;
+
+ /* UPA1 */
+ /* update predictor pole a[0] */
+ state_ptr->a[0] -= state_ptr->a[0] >> 8;
+ if (dqsez != 0) {
+ if (pks1 == 0)
+ state_ptr->a[0] += 192;
+ else
+ state_ptr->a[0] -= 192;
+ }
+
+ /* LIMD */
+ a1ul = 15360 - a2p;
+ if (state_ptr->a[0] < -a1ul)
+ state_ptr->a[0] = -a1ul;
+ else if (state_ptr->a[0] > a1ul)
+ state_ptr->a[0] = a1ul;
+
+ /* UPB : update predictor zeros b[6] */
+ for (cnt = 0; cnt < 6; cnt++) {
+ if (code_size == 5) /* for 40Kbps G.723 */
+ state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;
+ else /* for G.721 and 24Kbps G.723 */
+ state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
+ if (dq & 0x7FFF) { /* XOR */
+ if ((dq ^ state_ptr->dq[cnt]) >= 0)
+ state_ptr->b[cnt] += 128;
+ else
+ state_ptr->b[cnt] -= 128;
+ }
+ }
+ }
+
+ for (cnt = 5; cnt > 0; cnt--)
+ state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
+ /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
+ if (mag == 0) {
+ state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
+ } else {
+ exp = quan(mag, power2, 15);
+ state_ptr->dq[0] = (dq >= 0) ?
+ (exp << 6) + ((mag << 6) >> exp) :
+ (exp << 6) + ((mag << 6) >> exp) - 0x400;
+ }
+
+ state_ptr->sr[1] = state_ptr->sr[0];
+ /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
+ if (sr == 0) {
+ state_ptr->sr[0] = 0x20;
+ } else if (sr > 0) {
+ exp = quan(sr, power2, 15);
+ state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
+ } else if (sr > -32768) {
+ mag = -sr;
+ exp = quan(mag, power2, 15);
+ state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
+ } else
+ state_ptr->sr[0] = 0xFC20;
+
+ /* DELAY A */
+ state_ptr->pk[1] = state_ptr->pk[0];
+ state_ptr->pk[0] = pk0;
+
+ /* TONE */
+ if (tr == 1) /* this sample has been treated as data */
+ state_ptr->td = 0; /* next one will be treated as voice */
+ else if (a2p < -11776) /* small sample-to-sample correlation */
+ state_ptr->td = 1; /* signal may be data */
+ else /* signal is voice */
+ state_ptr->td = 0;
+
+ /*
+ * Adaptation speed control.
+ */
+ state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
+ state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
+
+ if (tr == 1)
+ state_ptr->ap = 256;
+ else if (y < 1536) /* SUBTC */
+ state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+ else if (state_ptr->td == 1)
+ state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+ else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
+ (state_ptr->dml >> 3))
+ state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
+ else
+ state_ptr->ap += (-state_ptr->ap) >> 4;
+}
+
+/*
+ * tandem_adjust(sr, se, y, i, sign)
+ *
+ * At the end of ADPCM decoding, it simulates an encoder which may be receiving
+ * the output of this decoder as a tandem process. If the output of the
+ * simulated encoder differs from the input to this decoder, the decoder output
+ * is adjusted by one level of A-law or u-law codes.
+ *
+ * Input:
+ * sr decoder output linear PCM sample,
+ * se predictor estimate sample,
+ * y quantizer step size,
+ * i decoder input code,
+ * sign sign bit of code i
+ *
+ * Return:
+ * adjusted A-law or u-law compressed sample.
+ */
+int
+tandem_adjust_alaw(
+ int sr, /* decoder output linear PCM sample */
+ int se, /* predictor estimate sample */
+ int y, /* quantizer step size */
+ int i, /* decoder input code */
+ int sign,
+ short *qtab)
+{
+ unsigned char sp; /* A-law compressed 8-bit code */
+ short dx; /* prediction error */
+ char id; /* quantized prediction error */
+ int sd; /* adjusted A-law decoded sample value */
+ int im; /* biased magnitude of i */
+ int imx; /* biased magnitude of id */
+
+ if (sr <= -32768)
+ sr = -1;
+ sp = linear2alaw((sr >> 1) << 3); /* short to A-law compression */
+ dx = (alaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
+ id = quantize(dx, y, qtab, sign - 1);
+
+ if (id == i) { /* no adjustment on sp */
+ return (sp);
+ } else { /* sp adjustment needed */
+ /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
+ im = i ^ sign; /* 2's complement to biased unsigned */
+ imx = id ^ sign;
+
+ if (imx > im) { /* sp adjusted to next lower value */
+ if (sp & 0x80) {
+ sd = (sp == 0xD5) ? 0x55 :
+ ((sp ^ 0x55) - 1) ^ 0x55;
+ } else {
+ sd = (sp == 0x2A) ? 0x2A :
+ ((sp ^ 0x55) + 1) ^ 0x55;
+ }
+ } else { /* sp adjusted to next higher value */
+ if (sp & 0x80)
+ sd = (sp == 0xAA) ? 0xAA :
+ ((sp ^ 0x55) + 1) ^ 0x55;
+ else
+ sd = (sp == 0x55) ? 0xD5 :
+ ((sp ^ 0x55) - 1) ^ 0x55;
+ }
+ return (sd);
+ }
+}
+
+int
+tandem_adjust_ulaw(
+ int sr, /* decoder output linear PCM sample */
+ int se, /* predictor estimate sample */
+ int y, /* quantizer step size */
+ int i, /* decoder input code */
+ int sign,
+ short *qtab)
+{
+ unsigned char sp; /* u-law compressed 8-bit code */
+ short dx; /* prediction error */
+ char id; /* quantized prediction error */
+ int sd; /* adjusted u-law decoded sample value */
+ int im; /* biased magnitude of i */
+ int imx; /* biased magnitude of id */
+
+ if (sr <= -32768)
+ sr = 0;
+ sp = linear2ulaw(sr << 2); /* short to u-law compression */
+ dx = (ulaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
+ id = quantize(dx, y, qtab, sign - 1);
+ if (id == i) {
+ return (sp);
+ } else {
+ /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
+ im = i ^ sign; /* 2's complement to biased unsigned */
+ imx = id ^ sign;
+ if (imx > im) { /* sp adjusted to next lower value */
+ if (sp & 0x80)
+ sd = (sp == 0xFF) ? 0x7E : sp + 1;
+ else
+ sd = (sp == 0) ? 0 : sp - 1;
+
+ } else { /* sp adjusted to next higher value */
+ if (sp & 0x80)
+ sd = (sp == 0x80) ? 0x80 : sp - 1;
+ else
+ sd = (sp == 0x7F) ? 0xFE : sp + 1;
+ }
+ return (sd);
+ }
+}
diff --git a/src/ccitt-adpcm/g72x.h b/src/ccitt-adpcm/g72x.h
new file mode 100644
index 0000000..3426176
--- /dev/null
+++ b/src/ccitt-adpcm/g72x.h
@@ -0,0 +1,148 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use. Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * g72x.h
+ *
+ * Header file for CCITT conversion routines.
+ *
+ */
+#ifndef _G72X_H
+#define _G72X_H
+
+#define AUDIO_ENCODING_ULAW (1) /* ISDN u-law */
+#define AUDIO_ENCODING_ALAW (2) /* ISDN A-law */
+#define AUDIO_ENCODING_LINEAR (3) /* PCM 2's-complement (0-center) */
+
+/*
+ * The following is the definition of the state structure
+ * used by the G.721/G.723 encoder and decoder to preserve their internal
+ * state between successive calls. The meanings of the majority
+ * of the state structure fields are explained in detail in the
+ * CCITT Recommendation G.721. The field names are essentially indentical
+ * to variable names in the bit level description of the coding algorithm
+ * included in this Recommendation.
+ */
+struct g72x_state {
+ long yl; /* Locked or steady state step size multiplier. */
+ short yu; /* Unlocked or non-steady state step size multiplier. */
+ short dms; /* Short term energy estimate. */
+ short dml; /* Long term energy estimate. */
+ short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */
+
+ short a[2]; /* Coefficients of pole portion of prediction filter. */
+ short b[6]; /* Coefficients of zero portion of prediction filter. */
+ short pk[2]; /*
+ * Signs of previous two samples of a partially
+ * reconstructed signal.
+ */
+ short dq[6]; /*
+ * Previous 6 samples of the quantized difference
+ * signal represented in an internal floating point
+ * format.
+ */
+ short sr[2]; /*
+ * Previous 2 samples of the quantized difference
+ * signal represented in an internal floating point
+ * format.
+ */
+ char td; /* delayed tone detect, new in 1988 version */
+};
+
+/* External function definitions. */
+
+extern void g72x_init_state(struct g72x_state *);
+extern int predictor_zero(struct g72x_state *state_ptr);
+extern int predictor_pole(struct g72x_state *state_ptr);
+extern int step_size(struct g72x_state *state_ptr);
+
+extern int quantize(
+ int d,
+ int y,
+ short *table,
+ int size);
+extern int reconstruct(
+ int sign,
+ int dqln,
+ int y);
+extern void update(
+ int code_size,
+ int y,
+ int wi,
+ int fi,
+ int dq,
+ int sr,
+ int dqsez,
+ struct g72x_state *state_ptr);
+
+extern int tandem_adjust_alaw(
+ int sr,
+ int se,
+ int y,
+ int i,
+ int sign,
+ short *qtab);
+extern int tandem_adjust_ulaw(
+ int sr,
+ int se,
+ int y,
+ int i,
+ int sign,
+ short *qtab);
+
+extern int g721_encoder(
+ int sample,
+ int in_coding,
+ struct g72x_state *state_ptr);
+extern int g721_decoder(
+ int code,
+ int out_coding,
+ struct g72x_state *state_ptr);
+extern int g723_24_encoder(
+ int sample,
+ int in_coding,
+ struct g72x_state *state_ptr);
+extern int g723_24_decoder(
+ int code,
+ int out_coding,
+ struct g72x_state *state_ptr);
+extern int g723_40_encoder(
+ int sample,
+ int in_coding,
+ struct g72x_state *state_ptr);
+extern int g723_40_decoder(
+ int code,
+ int out_coding,
+ struct g72x_state *state_ptr);
+
+extern unsigned char linear2alaw(int pcm_val);
+extern int alaw2linear(unsigned char a_val);
+extern unsigned char linear2ulaw(int pcm_val);
+extern int ulaw2linear(unsigned char u_val);
+extern unsigned char alaw2ulaw(unsigned char aval);
+extern unsigned char ulaw2alaw(unsigned char uval);
+
+#endif /* !_G72X_H */
diff --git a/src/dsaa.c b/src/dsaa.c
new file mode 100644
index 0000000..48db952
--- /dev/null
+++ b/src/dsaa.c
@@ -0,0 +1,211 @@
+/*
+ * From: https://dedected.org/trac/wiki/DSAA-Reversing
+ *
+ * FIXME: LICENSE? Copyrights?
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <libdect.h>
+
+static const uint8_t sbox[256] = {
+ 176, 104, 111, 246, 125, 232, 22, 133,
+ 57, 124, 127, 222, 67, 240, 89, 169,
+ 251, 128, 50, 174, 95, 37, 140, 245,
+ 148, 107, 216, 234, 136, 152, 194, 41,
+ 207, 58, 80, 150, 28, 8, 149, 244,
+ 130, 55, 10, 86, 44, 255, 79, 196,
+ 96, 165, 131, 33, 48, 248, 243, 40,
+ 250, 147, 73, 52, 66, 120, 191, 252,
+ 97, 198, 241, 167, 26, 83, 3, 77,
+ 134, 211, 4, 135, 126, 143, 160, 183,
+ 49, 179, 231, 14, 47, 204, 105, 195,
+ 192, 217, 200, 19, 220, 139, 1, 82,
+ 193, 72, 239, 175, 115, 221, 92, 46,
+ 25, 145, 223, 34, 213, 61, 13, 163,
+ 88, 129, 62, 253, 98, 68, 36, 45,
+ 182, 141, 90, 5, 23, 190, 39, 84,
+ 93, 157, 214, 173, 108, 237, 100, 206,
+ 242, 114, 63, 212, 70, 164, 16, 162,
+ 59, 137, 151, 76, 110, 116, 153, 228,
+ 227, 187, 238, 112, 0, 189, 101, 32,
+ 15, 122, 233, 158, 155, 199, 181, 99,
+ 230, 170, 225, 138, 197, 7, 6, 30,
+ 94, 29, 53, 56, 119, 20, 17, 226,
+ 185, 132, 24, 159, 42, 203, 218, 247,
+ 166, 178, 102, 123, 177, 156, 109, 106,
+ 249, 254, 202, 201, 168, 65, 188, 121,
+ 219, 184, 103, 186, 172, 54, 171, 146,
+ 75, 215, 229, 154, 118, 205, 21, 31,
+ 78, 74, 87, 113, 27, 85, 9, 81,
+ 51, 12, 180, 142, 43, 224, 208, 91,
+ 71, 117, 69, 64, 2, 209, 60, 236,
+ 35, 235, 11, 210, 161, 144, 38, 18,
+};
+
+static void bitperm(uint8_t start, uint8_t step, uint8_t * key)
+{
+ static uint8_t copy[8];
+ unsigned int i;
+
+ memcpy(copy, key, 8);
+ memset(key, 0, 8);
+
+ for (i = 0; i < 64; i++) {
+ key[start/8] |= ((copy[i / 8] & (1 << (i % 8))) >>
+ (i % 8)) << (start % 8);
+ start += step;
+ start %= 64;
+ }
+}
+
+#if 0
+static void bitperm1(uint8_t * key)
+{
+ bitperm(46, 35, key);
+}
+
+static void bitperm2(uint8_t * key)
+{
+ bitperm(25, 47, key);
+}
+
+static void bitperm3(uint8_t * key)
+{
+ bitperm(60, 27, key);
+}
+
+static void bitperm4(uint8_t * key)
+{
+ bitperm(55, 39, key);
+}
+#endif
+
+static const uint8_t mix_factor[3][8] = {
+ {2, 2, 2, 2, 3, 3, 3, 3},
+ {2, 2, 3, 3, 2, 2, 3, 3},
+ {2, 3, 2, 3, 2, 3, 2, 3},
+};
+
+static const uint8_t mix_index[3][8] = {
+ {4, 5, 6, 7, 0, 1, 2, 3},
+ {2, 3, 0, 1, 6, 7, 4, 5},
+ {1, 0, 3, 2, 5, 4, 7, 6},
+};
+
+static void mix(uint8_t start, uint8_t alg, uint8_t * key)
+{
+ unsigned int i;
+ uint8_t copy[8];
+
+ memcpy(copy, key, 8);
+ for (i=0; i<8; i++)
+ key[i] = copy[mix_index[alg][i]] + mix_factor[alg][i] * copy[i];
+}
+
+static void mix1(uint8_t * key)
+{
+ mix(4, 0, key);
+}
+
+static void mix2(uint8_t * key)
+{
+ mix(2, 1, key);
+}
+
+static void mix3(uint8_t * key)
+{
+ mix(1, 2, key);
+}
+
+static void sub(uint8_t * s, uint8_t * t)
+{
+ unsigned int i;
+
+ for (i = 0; i < 8; i++)
+ s[i] = sbox[s[i] ^ t[i]];
+}
+
+/* return in s */
+static void cassable(uint8_t start, uint8_t step, uint8_t * t, uint8_t * s)
+{
+ unsigned int i;
+
+ for(i = 0; i < 2; i++) {
+ bitperm(start, step, t);
+ sub(s, t);
+ mix1(s);
+
+ bitperm(start, step, t);
+ sub(s, t);
+ mix2(s);
+
+ bitperm(start, step, t);
+ sub(s, t);
+ mix3(s);
+ }
+}
+
+/* return in rand, modifies key */
+static void step1(uint8_t * rand, uint8_t * key)
+{
+
+ uint8_t tmp[8];
+
+ memcpy(tmp, rand, 8);
+
+ cassable(46, 35, tmp, key);
+ cassable(25, 47, key, rand);
+
+ memcpy(key, rand, 8);
+}
+
+static void step2(uint8_t * rand, uint8_t * key)
+{
+
+ uint8_t tmp[8];
+
+ memcpy(tmp, rand, 8);
+
+ cassable(60, 27, tmp, key);
+ cassable(55, 39, key, rand);
+
+ memcpy(key, rand, 8);
+}
+
+static void rev(uint8_t * v, uint8_t n)
+{
+ unsigned int i;
+ uint8_t tmp;
+
+ for (i = 0; i < n / 2; i++) {
+ tmp = v[i];
+ v[i] = v[n - i - 1];
+ v[n - i - 1] = tmp;
+ }
+}
+
+void dsaa_main(uint8_t * rand, uint8_t * key, uint8_t * out);
+void dsaa_main(uint8_t * rand, uint8_t * key, uint8_t * out)
+{
+ uint8_t a[8];
+ uint8_t b[8];
+
+ rev(rand, 8);
+ rev(key, 16);
+
+ step1(rand, key + 4);
+
+ memcpy(a, key + 4, 8);
+
+ memcpy(key + 4, key + 12, 4);
+ memcpy(b, a, 8);
+ step2(b, key);
+
+ rev(a, 8);
+ rev(key, 8);
+
+ memcpy(out, key, 4);
+ memcpy(out + 4, a, 8);
+ memcpy(out + 12, key + 4, 4);
+}
diff --git a/src/identities.c b/src/identities.c
new file mode 100644
index 0000000..4a66f15
--- /dev/null
+++ b/src/identities.c
@@ -0,0 +1,182 @@
+/*
+ * DECT Identities
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <asm/byteorder.h>
+
+#include <libdect.h>
+#include <identities.h>
+#include <utils.h>
+
+
+uint8_t dect_parse_ari(struct dect_ari *ari, uint64_t a)
+{
+ ari->arc = (a & DECT_ARI_ARC_MASK) >> DECT_ARI_ARC_SHIFT;
+ switch (ari->arc) {
+ case DECT_ARC_A:
+ ari->emc = (a & DECT_ARI_A_EMC_MASK) >> DECT_ARI_A_EMC_SHIFT;
+ ari->fpn = (a & DECT_ARI_A_FPN_MASK) >> DECT_ARI_A_FPN_SHIFT;
+ dect_debug("ARI class A: EMC: %.4x FPN: %.5x\n",
+ ari->emc, ari->fpn);
+ return DECT_ARC_A_LEN;
+ case DECT_ARC_B:
+ ari->eic = (a & DECT_ARI_B_EIC_MASK) >> DECT_ARI_B_EIC_SHIFT;
+ ari->fpn = (a & DECT_ARI_B_FPN_MASK) >> DECT_ARI_B_FPN_SHIFT;
+ ari->fps = (a & DECT_ARI_B_FPS_MASK) >> DECT_ARI_B_FPS_SHIFT;
+ return DECT_ARC_B_LEN;
+ case DECT_ARC_C:
+ ari->poc = (a & DECT_ARI_C_POC_MASK) >> DECT_ARI_C_POC_SHIFT;
+ ari->fpn = (a & DECT_ARI_C_FPN_MASK) >> DECT_ARI_C_FPN_SHIFT;
+ ari->fps = (a & DECT_ARI_C_FPS_MASK) >> DECT_ARI_C_FPS_SHIFT;
+ return DECT_ARC_C_LEN;
+ case DECT_ARC_D:
+ ari->gop = (a & DECT_ARI_D_GOP_MASK) >> DECT_ARI_D_GOP_SHIFT;
+ ari->fpn = (a & DECT_ARI_D_FPN_MASK) >> DECT_ARI_D_FPN_SHIFT;
+ return DECT_ARC_D_LEN;
+ case DECT_ARC_E:
+ ari->fil = (a & DECT_ARI_E_FIL_MASK) >> DECT_ARI_E_FIL_SHIFT;
+ ari->fpn = (a & DECT_ARI_E_FPN_MASK) >> DECT_ARI_E_FPN_SHIFT;
+ return DECT_ARC_E_LEN;
+ default:
+ return 0;
+ }
+}
+
+uint64_t dect_build_ari(const struct dect_ari *ari)
+{
+ uint64_t a = 0;
+
+ a |= (uint64_t)ari->arc << DECT_ARI_ARC_SHIFT;
+ switch (ari->arc) {
+ case DECT_ARC_A:
+ a |= (uint64_t)ari->emc << DECT_ARI_A_EMC_SHIFT;
+ a |= (uint64_t)ari->fpn << DECT_ARI_A_FPN_SHIFT;
+ break;
+ case DECT_ARC_B:
+ a |= (uint64_t)ari->eic << DECT_ARI_B_EIC_SHIFT;
+ a |= (uint64_t)ari->fpn << DECT_ARI_B_FPN_SHIFT;
+ a |= (uint64_t)ari->fps << DECT_ARI_B_FPS_SHIFT;
+ break;
+ case DECT_ARC_C:
+ a |= (uint64_t)ari->poc << DECT_ARI_C_POC_SHIFT;
+ a |= (uint64_t)ari->fpn << DECT_ARI_C_FPN_SHIFT;
+ a |= (uint64_t)ari->fps << DECT_ARI_C_FPS_SHIFT;
+ break;
+ case DECT_ARC_D:
+ a |= (uint64_t)ari->gop << DECT_ARI_D_GOP_SHIFT;
+ a |= (uint64_t)ari->fpn << DECT_ARI_D_FPN_SHIFT;
+ break;
+ case DECT_ARC_E:
+ a |= (uint64_t)ari->fil << DECT_ARI_E_FIL_SHIFT;
+ a |= (uint64_t)ari->fpn << DECT_ARI_E_FPN_SHIFT;
+ break;
+ }
+ return a;
+}
+
+static bool dect_parse_ipei(struct dect_ipei *ipei, uint64_t i)
+{
+ ipei->emc = (i & DECT_IPEI_EMC_MASK) >> DECT_IPEI_EMC_SHIFT;
+ ipei->psn = (i & DECT_IPEI_PSN_MASK);
+ dect_debug("IPEI: EMC: %.4x PSN: %.5x\n", ipei->emc, ipei->psn);
+ return true;
+}
+
+static uint64_t dect_build_ipei(const struct dect_ipei *ipei)
+{
+ uint64_t i = 0;
+
+ i |= (uint64_t)ipei->emc << DECT_IPEI_EMC_SHIFT;
+ i |= (uint64_t)ipei->psn;
+ return i;
+}
+
+bool dect_parse_ipui(struct dect_ipui *ipui, const uint8_t *ptr, uint8_t len)
+{
+ uint64_t tmp;
+
+ tmp = __be64_to_cpu(*(__be64 *)&ptr[0]) >> 24;
+
+ ipui->put = ptr[0] & DECT_IPUI_PUT_MASK;
+ switch (ipui->put) {
+ case DECT_IPUI_N:
+ if (len != 40)
+ return false;
+ return dect_parse_ipei(&ipui->pun.n.ipei, tmp);
+ case DECT_IPUI_O:
+ case DECT_IPUI_P:
+ case DECT_IPUI_Q:
+ case DECT_IPUI_R:
+ case DECT_IPUI_S:
+ case DECT_IPUI_T:
+ case DECT_IPUI_U:
+ default:
+ dect_debug("IPUI: unhandled type %u\n", ipui->put);
+ return false;
+ }
+}
+
+uint8_t dect_build_ipui(uint8_t *ptr, const struct dect_ipui *ipui)
+{
+ uint64_t tmp;
+
+ switch (ipui->put) {
+ case DECT_IPUI_N:
+ tmp = dect_build_ipei(&ipui->pun.n.ipei);
+ break;
+ case DECT_IPUI_O:
+ case DECT_IPUI_P:
+ case DECT_IPUI_Q:
+ case DECT_IPUI_R:
+ case DECT_IPUI_S:
+ case DECT_IPUI_T:
+ case DECT_IPUI_U:
+ return 0;
+ default:
+ return 0;
+ }
+
+ ptr[0] = ipui->put;
+ ptr[0] |= (tmp >> 32) & ~DECT_IPUI_PUT_MASK;
+ ptr[1] = tmp >> 24;
+ ptr[2] = tmp >> 16;
+ ptr[3] = tmp >> 8;
+ ptr[4] = tmp >> 0;
+ return 40;
+}
+
+bool dect_ipui_cmp(const struct dect_ipui *i1, const struct dect_ipui *i2)
+{
+ return memcmp(i1, i2, sizeof(*i1));
+}
+
+void dect_default_individual_tpui(struct dect_tpui *tpui,
+ const struct dect_ipui *ipui)
+{
+ tpui->tpui = DECT_TPUI_DEFAULT_INDIVIDUAL_ID;
+
+ switch (ipui->put) {
+ case DECT_IPUI_N:
+ tpui->tpui |= ipui->pun.n.ipei.psn &
+ DECT_TPUI_DEFAULT_INDIVIDUAL_IPUI_MASK;
+ break;
+ case DECT_IPUI_O:
+ case DECT_IPUI_P:
+ case DECT_IPUI_Q:
+ case DECT_IPUI_R:
+ case DECT_IPUI_S:
+ case DECT_IPUI_T:
+ case DECT_IPUI_U:
+ return;
+ }
+}
diff --git a/src/keypad.c b/src/keypad.c
new file mode 100644
index 0000000..bbca36f
--- /dev/null
+++ b/src/keypad.c
@@ -0,0 +1,80 @@
+/*
+ * DECT Keypad Protocol helpers
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <libdect.h>
+#include <dect/keypad.h>
+#include <utils.h>
+
+struct dect_keypad_buffer {
+ struct dect_timer *timer;
+ struct dect_ie_keypad keypad;
+ uint8_t timeout;
+ void *priv;
+ void (*complete)(struct dect_handle *, void *,
+ struct dect_ie_keypad *);
+};
+
+static void dect_keypad_timer(struct dect_handle *dh, struct dect_timer *timer)
+{
+ struct dect_keypad_buffer *kb = timer->data;
+
+ kb->complete(dh, kb->priv, &kb->keypad);
+}
+
+void dect_keypad_append(struct dect_handle *dh, struct dect_keypad_buffer *kb,
+ const struct dect_ie_keypad *keypad,
+ bool sending_complete)
+{
+ unsigned int len;
+
+ if (keypad->len > 0)
+ dect_stop_timer(dh, kb->timer);
+
+ len = sizeof(kb->keypad.info) - kb->keypad.len;
+ len = min((unsigned int)keypad->len, len);
+ memcpy(kb->keypad.info + kb->keypad.len, keypad->info, len);
+ kb->keypad.len += len;
+
+ if (sending_complete || kb->keypad.len == sizeof(kb->keypad.info))
+ kb->complete(dh, kb->priv, &kb->keypad);
+ else if (keypad->len > 0)
+ dect_start_timer(dh, kb->timer, kb->timeout);
+}
+
+struct dect_keypad_buffer *
+dect_keypad_buffer_init(const struct dect_handle *dh, uint8_t timeout,
+ void (*complete)(struct dect_handle *, void *priv,
+ struct dect_ie_keypad *keypad),
+ void *priv)
+{
+ struct dect_keypad_buffer *kb;
+
+ kb = dect_zalloc(dh, sizeof(*kb));
+ if (kb == NULL)
+ goto err1;
+
+ kb->timer = dect_alloc_timer(dh);
+ if (kb->timer == NULL)
+ goto err2;
+ kb->timer->callback = dect_keypad_timer;
+ kb->timer->data = kb;
+
+ kb->complete = complete;
+ kb->priv = priv;
+ kb->timeout = timeout;
+ return kb;
+
+err1:
+ dect_free(dh, kb);
+err2:
+ return NULL;
+}
diff --git a/src/lce.c b/src/lce.c
new file mode 100644
index 0000000..43d3ec7
--- /dev/null
+++ b/src/lce.c
@@ -0,0 +1,790 @@
+/*
+ * DECT Link Control Entity (LCE)
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/byteorder/little_endian.h>
+#include <linux/dect.h>
+#include <asm/byteorder.h>
+
+#include <libdect.h>
+#include <identities.h>
+#include <utils.h>
+#include <s_fmt.h>
+#include <b_fmt.h>
+#include <lce.h>
+#include <ss.h>
+
+static const struct dect_sfmt_ie_desc lce_page_response_msg[] = {
+ DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_NONE, IE_MANDATORY, 0),
+ DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_NWK_ASSIGNED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CIPHER_INFO, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc lce_page_reject_msg[] = {
+ DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_MANDATORY, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_REJECT_REASON, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_nwk_protocol *protocols[DECT_S_PD_MAX + 1];
+
+void dect_lce_register_protocol(const struct dect_nwk_protocol *protocol)
+{
+ protocols[protocol->pd] = protocol;
+}
+
+struct dect_msg_buf *dect_mbuf_alloc(const struct dect_handle *dh)
+{
+ struct dect_msg_buf *mb;
+
+ mb = dect_malloc(dh, sizeof(*mb));
+ if (mb == NULL)
+ return NULL;
+ memset(mb->head, 0, sizeof(mb->head));
+ mb->data = mb->head;
+ mb->len = 0;
+ mb->type = 0;
+ return mb;
+}
+
+static ssize_t dect_mbuf_rcv(const struct dect_fd *dfd, struct dect_msg_buf *mb)
+{
+ ssize_t len;
+
+ memset(mb, 0, sizeof(*mb));
+ mb->data = mb->head;
+ len = recv(dfd->fd, mb->data, sizeof(mb->head), 0);
+ if (len < 0)
+ return len;
+ mb->len = len;
+ return len;
+}
+
+#if 0
+/*
+ * Location Table
+ */
+
+static struct dect_lte *dect_lte_get_by_ipui(const struct dect_handle *dh,
+ const struct dect_ipui *ipui)
+{
+ struct dect_lte *lte;
+
+ list_for_each_entry(lte, &dh->ldb.entries, list) {
+ if (!dect_ipui_cmp(&lte->ipui, ipui))
+ return lte;
+ }
+ return NULL;
+}
+
+static struct dect_lte *dect_lte_alloc(const struct dect_handle *dh,
+ const struct dect_ipui *ipui)
+{
+ struct dect_lte *lte;
+
+ lte = dect_malloc(dh, sizeof(*lte));
+ if (lte == NULL)
+ return NULL;
+ memcpy(&lte->ipui, ipui, sizeof(lte->ipui));
+ return lte;
+}
+#endif
+
+/*
+ * Paging
+ */
+
+static int dect_lce_broadcast(const struct dect_handle *dh,
+ const uint8_t *msg, size_t len)
+{
+ ssize_t size;
+
+ dect_hexdump("BROADCAST", msg, len);
+ size = send(dh->b_sap->fd, msg, len, 0);
+ assert(size == (ssize_t)len);
+ return 0;
+}
+
+int dect_lce_group_ring(struct dect_handle *dh, enum dect_ring_patterns pattern)
+{
+ struct dect_short_page_msg msg;
+ uint16_t page;
+
+ msg.hdr = DECT_LCE_PAGE_W_FLAG;
+ msg.hdr |= DECT_LCE_PAGE_GENERAL_VOICE;
+
+ page = pattern << DECT_LCE_SHORT_PAGE_RING_PATTERN_SHIFT;
+ page = 0;
+ page |= DECT_TPUI_CBI & DECT_LCE_SHORT_PAGE_TPUI_MASK;
+ msg.information = __cpu_to_be16(page);
+
+ return dect_lce_broadcast(dh, &msg.hdr, sizeof(msg));
+}
+
+static int dect_lce_page(const struct dect_handle *dh,
+ const struct dect_ipui *ipui)
+{
+ struct dect_short_page_msg msg;
+ struct dect_tpui tpui;
+ uint16_t page;
+
+ dect_default_individual_tpui(&tpui, ipui);
+
+ msg.hdr = DECT_LCE_PAGE_GENERAL_VOICE;
+ page = tpui.tpui & DECT_LCE_SHORT_PAGE_TPUI_MASK;
+ msg.information = __cpu_to_be16(page);
+
+ return dect_lce_broadcast(dh, &msg.hdr, sizeof(msg));
+}
+
+static void dect_lce_rcv_short_page(struct dect_handle *dh,
+ struct dect_msg_buf *mb)
+{
+ struct dect_short_page_msg *msg = (void *)mb->data;
+ uint8_t hdr;
+ bool w;
+
+ w = msg->hdr & DECT_LCE_PAGE_W_FLAG;
+ hdr = msg->hdr & DECT_LCE_PAGE_HDR_MASK;
+ dect_debug("short page: w=%u hdr=%u information=%x\n",
+ w, hdr, __be16_to_cpu(msg->information));
+}
+
+static void dect_lce_bsap_event(struct dect_handle *dh, struct dect_fd *dfd,
+ uint32_t events)
+{
+ struct dect_msg_buf _mb, *mb = &_mb;
+
+ if (dect_mbuf_rcv(dfd, mb) < 0)
+ return;
+ dect_mbuf_dump(mb, "BCAST RX");
+
+ switch (mb->len) {
+ case 3:
+ return dect_lce_rcv_short_page(dh, mb);
+ default:
+ break;
+ }
+}
+
+/*
+ * Data links
+ */
+
+#define ddl_debug(ddl, fmt, args...) \
+ dect_debug("link %d (%s): " fmt "\n", \
+ (ddl)->dfd ? (ddl)->dfd->fd : -1, \
+ ddl_states[(ddl)->state], ## args)
+
+static const char *ddl_states[DECT_DATA_LINK_STATE_MAX + 1] = {
+ [DECT_DATA_LINK_RELEASED] = "RELEASED",
+ [DECT_DATA_LINK_ESTABLISHED] = "ESTABLISHED",
+ [DECT_DATA_LINK_ESTABLISH_PENDING] = "ESTABLISH_PENDING",
+ [DECT_DATA_LINK_RELEASE_PENDING] = "RELEASE_PENDING",
+ [DECT_DATA_LINK_SUSPENDED] = "SUSPENDED",
+ [DECT_DATA_LINK_SUSPEND_PENDING] = "SUSPEND_PENDING",
+ [DECT_DATA_LINK_RESUME_PENDING] = "RESUME_PENDING",
+};
+
+static struct dect_data_link *dect_ddl_get_by_ipui(const struct dect_handle *dh,
+ const struct dect_ipui *ipui)
+{
+ struct dect_data_link *ddl;
+
+ list_for_each_entry(ddl, &dh->links, list) {
+ if (!dect_ipui_cmp(&ddl->ipui, ipui))
+ return ddl;
+ }
+ return NULL;
+}
+
+static struct dect_transaction *
+dect_ddl_transaction_lookup(const struct dect_data_link *ddl, uint8_t pd, uint8_t tv)
+{
+ struct dect_transaction *ta;
+
+ list_for_each_entry(ta, &ddl->transactions, list) {
+ if (ta->pd == pd && ta->tv == tv)
+ return ta;
+ }
+ return NULL;
+}
+
+static void dect_ddl_destroy(struct dect_handle *dh, struct dect_data_link *ddl)
+{
+ struct dect_msg_buf *mb, *next;
+
+ ddl_debug(ddl, "destroy");
+ assert(ddl->sdu_timer == NULL);
+ assert(list_empty(&ddl->transactions));
+
+ list_del(&ddl->list);
+ list_for_each_entry_safe(mb, next, &ddl->msg_queue, list)
+ dect_free(dh, mb);
+ if (ddl->dfd != NULL) {
+ dect_unregister_fd(dh, ddl->dfd);
+ dect_close(dh, ddl->dfd);
+ }
+ dect_free(dh, ddl);
+}
+
+static struct dect_data_link *dect_ddl_alloc(const struct dect_handle *dh)
+{
+ struct dect_data_link *ddl;
+
+ ddl = dect_zalloc(dh, sizeof(*ddl));
+ if (ddl == NULL)
+ return NULL;
+ ddl->state = DECT_DATA_LINK_RELEASED;
+ init_list_head(&ddl->list);
+ init_list_head(&ddl->transactions);
+ init_list_head(&ddl->msg_queue);
+ ddl_debug(ddl, "alloc");
+ return ddl;
+}
+
+static void dect_ddl_sdu_timer(struct dect_handle *dh, struct dect_timer *timer)
+{
+ struct dect_data_link *ddl = timer->data;
+
+ ddl_debug(ddl, "SDU timer");
+ dect_free(dh, ddl->sdu_timer);
+ ddl->sdu_timer = NULL;
+ dect_ddl_destroy(dh, ddl);
+}
+
+static int dect_ddl_schedule_sdu_timer(const struct dect_handle *dh,
+ struct dect_data_link *ddl)
+{
+ ddl->sdu_timer = dect_alloc_timer(dh);
+ if (ddl->sdu_timer == NULL)
+ return -1;
+ ddl->sdu_timer->data = ddl;
+ ddl->sdu_timer->callback = dect_ddl_sdu_timer;
+ dect_start_timer(dh, ddl->sdu_timer, DECT_DDL_ESTABLISH_SDU_TIMEOUT);
+ ddl_debug(ddl, "start SDU timer");
+ return 0;
+}
+
+static void dect_ddl_stop_sdu_timer(const struct dect_handle *dh,
+ struct dect_data_link *ddl)
+{
+ ddl_debug(ddl, "stop SDU timer");
+ dect_stop_timer(dh, ddl->sdu_timer);
+ dect_free(dh, ddl->sdu_timer);
+ ddl->sdu_timer = NULL;
+}
+
+static int dect_send(const struct dect_handle *dh,
+ const struct dect_data_link *ddl,
+ struct dect_msg_buf *mb)
+{
+ ssize_t len;
+
+ dect_mbuf_dump(mb, "TX");
+ len = send(ddl->dfd->fd, mb->data, mb->len, 0);
+ assert(len == (ssize_t)mb->len);
+ dect_free(dh, mb);
+ return len;
+}
+
+/**
+ * dect_send - Queue a S-Format message for transmission to the LCE
+ *
+ */
+int dect_lce_send(const struct dect_handle *dh,
+ const struct dect_transaction *ta,
+ const struct dect_sfmt_ie_desc *desc,
+ const struct dect_msg_common *msg, uint8_t type,
+ const char *prefix)
+{
+ struct dect_data_link *ddl = ta->link;
+ struct dect_msg_buf *mb;
+
+ mb = dect_mbuf_alloc(dh);
+ if (mb == NULL)
+ return -1;
+
+ dect_mbuf_reserve(mb, DECT_S_HDR_SIZE);
+ dect_build_sfmt_msg(dh, desc, msg, mb);
+
+ if (ddl->sdu_timer != NULL)
+ dect_ddl_stop_sdu_timer(dh, ddl);
+
+ dect_mbuf_push(mb, DECT_S_HDR_SIZE);
+ mb->data[1] = type;
+ mb->data[0] = ta->pd;
+ mb->data[0] |= ta->tv << DECT_S_TI_TV_SHIFT;
+ if (ta->role == DECT_TRANSACTION_RESPONDER)
+ mb->data[0] |= DECT_S_TI_F_FLAG;
+
+ switch (ddl->state) {
+ case DECT_DATA_LINK_ESTABLISHED:
+ return dect_send(dh, ddl, mb);
+ case DECT_DATA_LINK_ESTABLISH_PENDING:
+ list_add_tail(&mb->list, &ddl->msg_queue);
+ return 0;
+ default:
+ BUG();
+ }
+}
+
+/**
+ * dect_ddl_establish - Establish an outgoing data link
+ *
+ */
+static void dect_lce_data_link_event(struct dect_handle *dh,
+ struct dect_fd *dfd, uint32_t events);
+
+static struct dect_data_link *dect_ddl_establish(struct dect_handle *dh,
+ const struct dect_ipui *ipui)
+{
+ struct dect_data_link *ddl;
+
+ //lte = dect_lte_get_by_ipui(dh, lte);
+ ddl = dect_ddl_alloc(dh);
+ if (ddl == NULL)
+ goto err1;
+ ddl->state = DECT_DATA_LINK_ESTABLISH_PENDING;
+
+ if (dh->mode == DECT_MODE_FP) {
+ memcpy(&ddl->ipui, ipui, sizeof(ddl->ipui));
+ dect_lce_page(dh, ipui);
+ } else {
+ ddl->dfd = dect_socket(dh, SOCK_SEQPACKET, DECT_S_SAP);
+ if (ddl->dfd == NULL)
+ goto err2;
+
+ ddl->dlei.dect_family = AF_DECT;
+ ddl->dlei.dect_ari = dect_build_ari(&dh->pari) >> 24;
+ ddl->dlei.dect_pmid = 0xe98a1;
+ ddl->dlei.dect_lln = 1;
+ ddl->dlei.dect_sapi = 0;
+
+ ddl->dfd->callback = dect_lce_data_link_event;
+ ddl->dfd->data = ddl;
+ if (dect_register_fd(dh, ddl->dfd, DECT_FD_WRITE) < 0)
+ goto err2;
+
+ if (connect(ddl->dfd->fd, (struct sockaddr *)&ddl->dlei,
+ sizeof(ddl->dlei)) < 0 && errno != EAGAIN)
+ perror("connect\n");
+ }
+
+ list_add_tail(&ddl->list, &dh->links);
+ return ddl;
+
+err2:
+ dect_free(dh, ddl);
+err1:
+ return NULL;
+}
+
+#if 0
+int dect_send_reject(const struct dect_handle *dh,
+ const struct dect_transaction *ta,
+ enum dect_reject_reasons reason)
+{
+ struct dect_ie_reject_reason reject_reason;
+ struct dect_lce_page_reject msg = {
+ .portable_identity = NULL,
+ .reject_reason = &reject_reason,
+ };
+
+ dect_send(dh, ta, mb);
+}
+#endif
+
+static void dect_ddl_complete_direct_establish(struct dect_handle *dh,
+ struct dect_data_link *ddl)
+{
+ struct dect_msg_buf *mb, *mb_next;
+
+ ddl->state = DECT_DATA_LINK_ESTABLISHED;
+ ddl_debug(ddl, "complete direct link establishment");
+
+ /* Send queued messages */
+ list_for_each_entry_safe(mb, mb_next, &ddl->msg_queue, list) {
+ list_del(&mb->list);
+ dect_send(dh, ddl, mb);
+ }
+
+ dect_unregister_fd(dh, ddl->dfd);
+ dect_register_fd(dh, ddl->dfd, DECT_FD_READ);
+}
+
+static void dect_ddl_complete_indirect_establish(struct dect_handle *dh,
+ struct dect_data_link *ddl,
+ struct dect_data_link *req)
+{
+ struct dect_transaction *ta, *ta_next;
+ struct dect_msg_buf *mb, *mb_next;
+
+ ddl_debug(ddl, "complete indirect link establishment req %p", req);
+ /* Transfer transactions to the new link */
+ list_for_each_entry_safe(ta, ta_next, &req->transactions, list) {
+ ddl_debug(ta->link, "transfer transaction to link %p\n", ddl);
+ list_move_tail(&ta->list, &ddl->transactions);
+ ta->link = ddl;
+ }
+
+ /* Send queued messages */
+ list_for_each_entry_safe(mb, mb_next, &req->msg_queue, list) {
+ list_del(&mb->list);
+ dect_send(dh, ddl, mb);
+ }
+
+ /* Release pending link */
+ dect_ddl_destroy(dh, req);
+}
+
+static void dect_lce_rcv_page_response(struct dect_handle *dh,
+ const struct dect_transaction *ta,
+ struct dect_msg_buf *mb)
+{
+ struct dect_lce_page_response msg;
+ struct dect_data_link *i, *req = NULL;
+
+ ddl_debug(ta->link, "LCE-PAGE-RESPONSE");
+ if (dect_parse_sfmt_msg(dh, lce_page_response_msg, &msg.common, mb) < 0)
+ return;
+
+ dect_debug("portable_identity: %p\n", msg.portable_identity);
+ dect_debug("fixed identity: %p\n", msg.fixed_identity);
+ dect_debug("nwk assigned identity: %p\n", msg.nwk_assigned_identity);
+ dect_debug("cipher info: %p\n", msg.cipher_info);
+ dect_debug("escape: %p\n", msg.escape_to_proprietary);
+
+ list_for_each_entry(i, &dh->links, list) {
+ if (dect_ipui_cmp(&i->ipui, &msg.portable_identity->ipui))
+ continue;
+ if (i->state != DECT_DATA_LINK_ESTABLISH_PENDING)
+ continue;
+ req = i;
+ break;
+ }
+
+ if (req != NULL)
+ dect_ddl_complete_indirect_establish(dh, ta->link, req);
+ else {
+ /* send page reject */
+ dect_ddl_destroy(dh, ta->link);
+ }
+
+ dect_msg_free(dh, lce_page_response_msg, &msg.common);
+}
+
+static void dect_lce_rcv_page_reject(struct dect_handle *dh,
+ struct dect_transaction *ta,
+ struct dect_msg_buf *mb)
+{
+ struct dect_lce_page_reject msg;
+
+ ddl_debug(ta->link, "LCE-PAGE-REJECT");
+ if (dect_parse_sfmt_msg(dh, lce_page_reject_msg, &msg.common, mb) < 0)
+ return;
+ dect_msg_free(dh, lce_page_reject_msg, &msg.common);
+}
+
+static void dect_lce_rcv(struct dect_handle *dh, struct dect_transaction *ta,
+ struct dect_msg_buf *mb)
+{
+ switch (mb->type) {
+ case DECT_LCE_PAGE_REJECT:
+ return dect_lce_rcv_page_reject(dh, ta, mb);
+ default:
+ ddl_debug(ta->link, "LCE: unknown message type %x", mb->type);
+ return;
+ }
+}
+
+static void dect_lce_open(struct dect_handle *dh,
+ const struct dect_transaction *ta,
+ struct dect_msg_buf *mb)
+{
+ switch (mb->type) {
+ case DECT_LCE_PAGE_RESPONSE:
+ return dect_lce_rcv_page_response(dh, ta, mb);
+ default:
+ ddl_debug(ta->link, "LCE: unknown message type %x", mb->type);
+ return;
+ }
+}
+
+static const struct dect_nwk_protocol lce_protocol = {
+ .name = "Link Control",
+ .pd = DECT_S_PD_LCE,
+ .max_transactions = 1,
+ .open = dect_lce_open,
+ .rcv = dect_lce_rcv,
+};
+
+static void dect_ddl_rcv_msg(struct dect_handle *dh, struct dect_data_link *ddl)
+{
+ struct dect_msg_buf _mb, *mb = &_mb;
+ struct dect_transaction *ta;
+ uint8_t pd, tv;
+ bool f;
+
+ if (ddl->sdu_timer != NULL)
+ dect_ddl_stop_sdu_timer(dh, ddl);
+
+ if (dect_mbuf_rcv(ddl->dfd, mb) < 0)
+ return;
+ dect_mbuf_dump(mb, "RX");
+
+ if (mb->len < DECT_S_HDR_SIZE)
+ return;
+ f = (mb->data[0] & DECT_S_TI_F_FLAG);
+ tv = (mb->data[0] & DECT_S_TI_TV_MASK) >> DECT_S_TI_TV_SHIFT;
+ pd = (mb->data[0] & DECT_S_PD_MASK);
+ mb->type = (mb->data[1] & DECT_S_PD_MSG_TYPE_MASK);
+ dect_mbuf_pull(mb, DECT_S_HDR_SIZE);
+
+ if (pd >= array_size(protocols) || protocols[pd] == NULL) {
+ ddl_debug(ddl, "unknown protocol %u\n", pd);
+ return;
+ }
+
+ if (tv == DECT_TV_CONNECTIONLESS)
+ return dect_clss_rcv(dh, mb);
+
+ ta = dect_ddl_transaction_lookup(ddl, pd, tv);
+ if (ta == NULL) {
+ struct dect_transaction req = {
+ .link = ddl,
+ .pd = pd,
+ .role = DECT_TRANSACTION_RESPONDER,
+ .tv = tv,
+ };
+ ddl_debug(ddl, "new transaction: protocol: %s F: %u TV: %u",
+ protocols[pd]->name, f, tv);
+ protocols[pd]->open(dh, &req, mb);
+ } else
+ protocols[pd]->rcv(dh, ta, mb);
+}
+
+static void dect_lce_data_link_event(struct dect_handle *dh,
+ struct dect_fd *dfd, uint32_t events)
+{
+ struct dect_data_link *ddl = dfd->data;
+
+ if (events & DECT_FD_WRITE) {
+ switch (ddl->state) {
+ case DECT_DATA_LINK_ESTABLISH_PENDING:
+ dect_ddl_complete_direct_establish(dh, ddl);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (events & DECT_FD_READ) {
+ dect_ddl_rcv_msg(dh, ddl);
+ }
+}
+
+static int dect_transaction_alloc_tv(const struct dect_data_link *ddl,
+ const struct dect_nwk_protocol *protocol)
+{
+ uint16_t tv;
+
+ for (tv = 0; tv < protocol->max_transactions; tv++) {
+ if (dect_ddl_transaction_lookup(ddl, protocol->pd, tv))
+ continue;
+ return tv;
+ }
+ return -1;
+}
+
+int dect_open_transaction(struct dect_handle *dh, struct dect_transaction *ta,
+ const struct dect_ipui *ipui)
+{
+ struct dect_data_link *ddl;
+ int tv;
+
+ ddl = dect_ddl_get_by_ipui(dh, ipui);
+ if (ddl == NULL) {
+ ddl = dect_ddl_establish(dh, ipui);
+ if (ddl == NULL)
+ return -1;
+ }
+
+ ddl_debug(ddl, "open transaction");
+ tv = dect_transaction_alloc_tv(ddl, protocols[ta->pd]);
+ if (tv < 0)
+ return -1;
+
+ ta->link = ddl;
+ ta->role = DECT_TRANSACTION_INITIATOR;
+ ta->tv = tv;
+
+ list_add_tail(&ta->list, &ddl->transactions);
+ return 0;
+}
+
+void dect_confirm_transaction(struct dect_handle *dh, struct dect_transaction *ta,
+ const struct dect_transaction *req)
+{
+ ta->link = req->link;
+ ta->tv = req->tv;
+ ta->role = req->role;
+ ta->pd = req->pd;
+
+ ddl_debug(req->link, "confirm transaction");
+ list_add_tail(&ta->list, &req->link->transactions);
+}
+
+void dect_close_transaction(struct dect_handle *dh, struct dect_transaction *ta)
+{
+ struct dect_data_link *ddl = ta->link;
+
+ ddl_debug(ddl, "close transaction");
+ list_del(&ta->list);
+ list_for_each_entry(ta, &ddl->transactions, list)
+ dect_debug("\ttrans %p proto %u TV %u\n", ta, ta->pd, ta->tv);
+ if (!list_empty(&ddl->transactions))
+ return;
+ dect_ddl_destroy(dh, ddl);
+}
+
+void dect_transaction_get_ulei(struct sockaddr_dect_lu *addr,
+ const struct dect_transaction *ta)
+{
+ struct dect_data_link *ddl = ta->link;
+
+ memset(addr, 0, sizeof(*addr));
+ addr->dect_family = AF_DECT;
+ addr->dect_ari = ddl->dlei.dect_ari;
+ addr->dect_pmid = ddl->dlei.dect_pmid;
+ addr->dect_lcn = ddl->dlei.dect_lcn;
+}
+
+static void dect_lce_ssap_listener_event(struct dect_handle *dh,
+ struct dect_fd *dfd, uint32_t events)
+{
+ struct dect_data_link *ddl;
+ struct dect_fd *nfd;
+
+ ddl = dect_ddl_alloc(dh);
+ if (ddl == NULL)
+ goto err1;
+
+ nfd = dect_accept(dh, dfd, (struct sockaddr *)&ddl->dlei,
+ sizeof(ddl->dlei));
+ if (nfd == NULL)
+ goto err2;
+ ddl->dfd = nfd;
+
+ nfd->callback = dect_lce_data_link_event;
+ nfd->data = ddl;
+ if (dect_register_fd(dh, nfd, DECT_FD_READ) < 0)
+ goto err3;
+
+ ddl->state = DECT_DATA_LINK_ESTABLISHED;
+ if (dect_ddl_schedule_sdu_timer(dh, ddl) < 0)
+ goto err4;
+
+ list_add_tail(&ddl->list, &dh->links);
+ ddl_debug(ddl, "new link: PMID: %x LCN: %u LLN: %u SAPI: %u",
+ ddl->dlei.dect_pmid, ddl->dlei.dect_lcn,
+ ddl->dlei.dect_lln, ddl->dlei.dect_sapi);
+ return;
+
+err4:
+ dect_unregister_fd(dh, nfd);
+err3:
+ dect_close(dh, nfd);
+err2:
+ dect_free(dh, ddl);
+err1:
+ return;
+}
+
+int dect_lce_init(struct dect_handle *dh)
+{
+ struct sockaddr_dect_ssap s_addr;
+ struct sockaddr_dect b_addr;
+
+ /* Open B-SAP socket */
+ dh->b_sap = dect_socket(dh, SOCK_DGRAM, DECT_B_SAP);
+ if (dh->b_sap == NULL)
+ goto err1;
+
+ b_addr.dect_family = AF_DECT;
+ b_addr.dect_index = dh->index;
+ if (bind(dh->b_sap->fd, (struct sockaddr *)&b_addr, sizeof(b_addr)) < 0)
+ goto err2;
+
+ dh->b_sap->callback = dect_lce_bsap_event;
+ if (dect_register_fd(dh, dh->b_sap, DECT_FD_READ) < 0)
+ goto err2;
+
+ /* Open S-SAP listener socket */
+ dh->s_sap = dect_socket(dh, SOCK_SEQPACKET, DECT_S_SAP);
+ if (dh->s_sap == NULL)
+ goto err3;
+
+ memset(&s_addr, 0, sizeof(s_addr));
+ s_addr.dect_family = AF_DECT;
+ s_addr.dect_lln = 1;
+ s_addr.dect_sapi = 0;
+
+ if (bind(dh->s_sap->fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0)
+ goto err4;
+ if (listen(dh->s_sap->fd, 10) < 0)
+ goto err4;
+
+ dh->s_sap->callback = dect_lce_ssap_listener_event;
+ if (dect_register_fd(dh, dh->s_sap, DECT_FD_READ) < 0)
+ goto err4;
+
+ protocols[DECT_S_PD_LCE] = &lce_protocol;
+ return 0;
+
+err4:
+ dect_close(dh, dh->s_sap);
+err3:
+ dect_unregister_fd(dh, dh->b_sap);
+err2:
+ dect_close(dh, dh->b_sap);
+err1:
+ return -1;
+}
+
+void dect_lce_exit(struct dect_handle *dh)
+{
+ struct dect_data_link *ddl, *ddl_next;
+ struct dect_transaction *ta, *ta_next;
+ LIST_HEAD(transactions);
+
+ list_for_each_entry_safe(ddl, ddl_next, &dh->links, list) {
+ ddl_debug(ddl, "shutdown");
+ list_splice_init(&ddl->transactions, &transactions);
+ list_for_each_entry_safe(ta, ta_next, &transactions, list)
+ protocols[ta->pd]->shutdown(dh, ta);
+ }
+
+ dect_unregister_fd(dh, dh->s_sap);
+ dect_close(dh, dh->s_sap);
+
+ dect_unregister_fd(dh, dh->b_sap);
+ dect_close(dh, dh->b_sap);
+}
diff --git a/src/libdect.c b/src/libdect.c
new file mode 100644
index 0000000..a3c006e
--- /dev/null
+++ b/src/libdect.c
@@ -0,0 +1,81 @@
+/*
+ * libdect public API functions
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include <libdect.h>
+#include <netlink.h>
+#include <utils.h>
+#include <lce.h>
+
+static void __fmtstring(1, 0) (*debug_hook)(const char *fmt, va_list ap);
+
+void dect_set_debug_hook(void (*fn)(const char *fmt, va_list ap))
+{
+ debug_hook = fn;
+}
+
+void __fmtstring(1, 2) dect_debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (debug_hook != NULL)
+ debug_hook(fmt, ap);
+ else
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+struct dect_handle *dect_alloc_handle(struct dect_ops *ops)
+{
+ struct dect_handle *dh;
+
+ if (ops->malloc == NULL)
+ ops->malloc = malloc;
+ if (ops->free == NULL)
+ ops->free = free;
+
+ dh = ops->malloc(sizeof(*dh));
+ if (dh == NULL)
+ return NULL;
+ dh->ops = ops;
+ init_list_head(&dh->links);
+ return dh;
+}
+
+int dect_init(struct dect_handle *dh)
+{
+ int err;
+
+ err = dect_netlink_init(dh);
+ if (err < 0)
+ goto err1;
+
+ err = dect_lce_init(dh);
+ if (err < 0)
+ goto err2;
+ return 0;
+
+err2:
+ dect_netlink_exit(dh);
+err1:
+ return err;
+}
+
+void dect_close_handle(struct dect_handle *dh)
+{
+ dect_lce_exit(dh);
+ dect_netlink_exit(dh);
+ dect_free(dh, dh);
+}
diff --git a/src/mm.c b/src/mm.c
new file mode 100644
index 0000000..0ae11f6
--- /dev/null
+++ b/src/mm.c
@@ -0,0 +1,154 @@
+/*
+ * DECT Mobility Management (MM)
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/dect.h>
+
+#include <libdect.h>
+#include <utils.h>
+#include <s_fmt.h>
+#include <lce.h>
+#include <mm.h>
+
+static const struct dect_sfmt_ie_desc mm_access_rights_request_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_NONE, IE_MANDATORY, 0),
+ DECT_SFMT_IE(S_VL_IE_AUTH_TYPE, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CIPHER_INFO, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_SETUP_CAPABILITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_TERMINAL_CAPABILITY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_MODEL_IDENTIFIER, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+static const struct dect_sfmt_ie_desc mm_access_rights_reject_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_REJECT_REASON, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_DURATION, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+#define mm_debug(fmt, args...) \
+ dect_debug("MM: " fmt "\n", ## args)
+
+int dect_mm_access_rights_req(struct dect_handle *dh,
+ const struct dect_mm_access_rights_param *param)
+{
+ static struct dect_transaction transaction;
+ struct dect_ipui ipui;
+ struct dect_mm_access_rights_request_msg msg = {
+ .portable_identity = param->portable_identity,
+ .auth_type = param->auth_type,
+ .cipher_info = param->cipher_info,
+ .setup_capability = NULL,
+ //.terminal_capability = param->terminal_capability,
+ .model_identifier = param->model_identifier,
+ .codec_list = NULL,
+ .escape_to_proprietary = NULL,
+ };
+
+ mm_debug("access rights request");
+ transaction.pd = DECT_S_PD_MM;
+
+ if (dect_open_transaction(dh, &transaction, &ipui) < 0)
+ goto err1;
+
+ if (dect_lce_send(dh, &transaction, mm_access_rights_request_msg_desc,
+ &msg.common, DECT_MM_ACCESS_RIGHTS_REQUEST,
+ "MM-ACCESS_RIGHTS_REQUEST") < 0)
+ goto err2;
+ return 0;
+
+err2:
+ dect_close_transaction(dh, &transaction);
+err1:
+ return -1;
+}
+
+static void dect_mm_rcv_access_rights_reject(struct dect_handle *dh,
+ struct dect_msg_buf *mb)
+{
+ struct dect_mm_access_rights_reject_msg msg;
+
+ if (dect_parse_sfmt_msg(dh, mm_access_rights_reject_msg_desc, &msg.common, mb) < 0)
+ return;
+}
+
+static void dect_mm_rcv(struct dect_handle *dh, struct dect_transaction *ta,
+ struct dect_msg_buf *mb)
+{
+ mm_debug("receive msg type %x", mb->type);
+ switch (mb->type) {
+ case DECT_MM_AUTHENTICATION_REQUEST:
+ case DECT_MM_AUTHENTICATION_REPLY:
+ case DECT_MM_KEY_ALLOCATE:
+ case DECT_MM_AUTHENTICATION_REJECT:
+ case DECT_MM_ACCESS_RIGHTS_REQUEST:
+ break;
+ case DECT_MM_ACCESS_RIGHTS_ACCEPT:
+ break;
+ case DECT_MM_ACCESS_RIGHTS_REJECT:
+ return dect_mm_rcv_access_rights_reject(dh, mb);
+ case DECT_MM_ACCESS_RIGHTS_TERMINATE_REQUEST:
+ case DECT_MM_ACCESS_RIGHTS_TERMINATE_ACCEPT:
+ case DECT_MM_ACCESS_RIGHTS_TERMINATE_REJECT:
+ case DECT_MM_CIPHER_REQUEST:
+ case DECT_MM_CIPHER_SUGGEST:
+ case DECT_MM_CIPHER_REJECT:
+ case DECT_MM_INFO_REQUEST:
+ case DECT_MM_INFO_ACCEPT:
+ case DECT_MM_INFO_SUGGEST:
+ case DECT_MM_INFO_REJECT:
+ case DECT_MM_LOCATE_REQUEST:
+ case DECT_MM_LOCATE_ACCEPT:
+ case DECT_MM_DETACH:
+ case DECT_MM_LOCATE_REJECT:
+ case DECT_MM_IDENTITY_REQUEST:
+ case DECT_MM_IDENTITY_REPLY:
+ case DECT_MM_TEMPORARY_IDENTITY_ASSIGN:
+ case DECT_MM_TEMPORARY_IDENTITY_ASSIGN_ACK:
+ case DECT_MM_TEMPORARY_IDENTITY_ASSIGN_REJ:
+ break;
+ }
+}
+
+static void dect_mm_open(struct dect_handle *dh,
+ const struct dect_transaction *req,
+ struct dect_msg_buf *mb)
+{
+ dect_debug("MM: unknown transaction msg type: %x\n", mb->type);
+
+ switch (mb->type) {
+ default:
+ break;
+ }
+}
+
+static const struct dect_nwk_protocol mm_protocol = {
+ .name = "Mobility Management",
+ .pd = DECT_S_PD_MM,
+ .max_transactions = 1,
+ .open = dect_mm_open,
+ //.shutdown = dect_mm_shutdown,
+ .rcv = dect_mm_rcv,
+};
+
+static void __init dect_mm_init(void)
+{
+ dect_lce_register_protocol(&mm_protocol);
+}
diff --git a/src/netlink.c b/src/netlink.c
new file mode 100644
index 0000000..72099e4
--- /dev/null
+++ b/src/netlink.c
@@ -0,0 +1,139 @@
+/*
+ * DECT Netlink Interface
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <netlink/netlink.h>
+#include <netlink/object.h>
+#include <netlink/msg.h>
+#include <netlink/dect/cluster.h>
+#include <netlink/dect/ari.h>
+
+#include <libdect.h>
+#include <netlink.h>
+#include <utils.h>
+
+static void dect_netlink_event(struct dect_handle *dh, struct dect_fd *fd,
+ uint32_t event)
+{
+ nl_recvmsgs_default(dh->nlsock);
+}
+
+static void dect_netlink_set_callback(struct dect_handle *dh,
+ nl_recvmsg_msg_cb_t func,
+ void *arg)
+{
+ nl_socket_modify_cb(dh->nlsock, NL_CB_VALID, NL_CB_CUSTOM, func, arg);
+}
+
+static void dect_netlink_parse_ari(struct dect_ari *ari, const struct nl_dect_ari *nlari)
+{
+ ari->arc = nl_dect_ari_get_class(nlari);
+ switch (ari->arc) {
+ case DECT_ARC_A:
+ ari->emc = nl_dect_ari_get_emc(nlari);
+ ari->fpn = nl_dect_ari_get_fpn(nlari);
+ dect_debug("ARI class A: EMC: %.4x FPN: %.5x\n",
+ ari->emc, ari->fpn);
+ break;
+ case DECT_ARC_B:
+ ari->eic = nl_dect_ari_get_eic(nlari);
+ ari->fpn = nl_dect_ari_get_fpn(nlari);
+ ari->fps = nl_dect_ari_get_fps(nlari);
+ break;
+ case DECT_ARC_C:
+ ari->poc = nl_dect_ari_get_poc(nlari);
+ ari->fpn = nl_dect_ari_get_fpn(nlari);
+ ari->fps = nl_dect_ari_get_fps(nlari);
+ break;
+ case DECT_ARC_D:
+ ari->gop = nl_dect_ari_get_gop(nlari);
+ ari->fpn = nl_dect_ari_get_fpn(nlari);
+ break;
+ case DECT_ARC_E:
+ ari->fil = nl_dect_ari_get_fil(nlari);
+ ari->fpn = nl_dect_ari_get_fpn(nlari);
+ break;
+ }
+}
+
+static void get_cluster_cb(struct nl_object *obj, void *arg)
+{
+ struct dect_handle *dh = arg;
+ struct nl_dect_cluster *cl = (struct nl_dect_cluster *)obj;
+
+ dh->index = nl_dect_cluster_get_index(cl);
+ dh->mode = nl_dect_cluster_get_mode(cl);
+ dect_netlink_parse_ari(&dh->pari, nl_dect_cluster_get_pari(cl));
+}
+
+static int dect_netlink_get_cluster_cb(struct nl_msg *msg, void *arg)
+{
+ return nl_msg_parse(msg, get_cluster_cb, arg);
+}
+
+int dect_netlink_init(struct dect_handle *dh)
+{
+ struct nl_dect_cluster *cl;
+ int err;
+
+ dh->nlsock = nl_socket_alloc();
+ if (dh->nlsock == NULL)
+ goto err1;
+
+ err = nl_connect(dh->nlsock, NETLINK_DECT);
+ if (err < 0)
+ goto err2;
+
+ err = nl_socket_set_nonblocking(dh->nlsock);
+ if (err < 0)
+ goto err2;
+
+ dh->nlfd = dect_alloc_fd(dh);
+ if (dh->nlfd == NULL)
+ goto err2;
+ dh->nlfd->fd = nl_socket_get_fd(dh->nlsock);
+
+ dh->nlfd->callback = dect_netlink_event;
+ if (dect_register_fd(dh, dh->nlfd, DECT_FD_READ))
+ goto err3;
+
+ cl = nl_dect_cluster_alloc();
+ if (cl == NULL)
+ goto err4;
+ nl_dect_cluster_set_name(cl, "cluster0");
+
+ dect_netlink_set_callback(dh, dect_netlink_get_cluster_cb, dh);
+ err = nl_dect_cluster_query(dh->nlsock, cl, 0);
+ dect_netlink_set_callback(dh, NULL, NULL);
+ if (err < 0)
+ goto err5;
+
+ return 0;
+err5:
+ nl_dect_cluster_put(cl);
+err4:
+ dect_unregister_fd(dh, dh->nlfd);
+err3:
+ dect_free(dh, dh->nlfd);
+err2:
+ nl_close(dh->nlsock);
+err1:
+ return -1;
+}
+
+void dect_netlink_exit(struct dect_handle *dh)
+{
+ dect_unregister_fd(dh, dh->nlfd);
+ nl_close(dh->nlsock);
+ dect_free(dh, dh->nlfd);
+}
diff --git a/src/s_msg.c b/src/s_msg.c
new file mode 100644
index 0000000..1eac658
--- /dev/null
+++ b/src/s_msg.c
@@ -0,0 +1,991 @@
+/*
+ * DECT S-Format messages
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <asm/byteorder.h>
+
+#include <libdect.h>
+#include <identities.h>
+#include <utils.h>
+#include <s_fmt.h>
+#include <lce.h>
+
+static struct dect_ie_common *dect_ie_alloc(const struct dect_handle *dh,
+ unsigned int size)
+{
+ struct dect_ie_common *ie;
+
+ ie = dect_zalloc(dh, size);
+ if (ie == NULL)
+ return NULL;
+ __dect_ie_init(ie);
+ return ie;
+}
+
+static int dect_sfmt_parse_repeat_indicator(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_repeat_indicator *dst = dect_ie_container(dst, *ie);
+
+ init_list_head(&dst->list);
+ dst->type = src->data[0] & DECT_SFMT_IE_FIXED_VAL_MASK;
+ switch (dst->type) {
+ case DECT_SFMT_IE_LIST_NORMAL:
+ case DECT_SFMT_IE_LIST_PRIORITIZED:
+ return 0;
+ default:
+ dect_debug("invalid list type\n");
+ return -1;
+ }
+}
+
+static int dect_sfmt_build_repeat_indicator(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie)
+{
+ struct dect_ie_repeat_indicator *src = dect_ie_container(src, ie);
+
+ dect_debug("build repeat indicator list %p %p\n", src->list.prev, src->list.next);
+ dst->data[0] = src->type;
+ return 0;
+}
+
+static int dect_sfmt_parse_empty_single_octet(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ return 0;
+}
+
+static int dect_sfmt_build_empty_single_octet(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie)
+{
+ dst->data[0] = 0;
+ return 0;
+}
+
+static const char *call_classes[DECT_CALL_CLASS_MAX + 1] = {
+ [DECT_CALL_CLASS_MESSAGE] = "message call",
+ [DECT_CALL_CLASS_DECT_ISDN] = "DECT/ISDN IIP",
+ [DECT_CALL_CLASS_NORMAL] = "normal call",
+ [DECT_CALL_CLASS_INTERNAL] = "internal call",
+ [DECT_CALL_CLASS_EMERGENCY] = "emergency call",
+ [DECT_CALL_CLASS_SERVICE] = "service call",
+ [DECT_CALL_CLASS_EXTERNAL_HO] = "external handover call",
+ [DECT_CALL_CLASS_SUPPLEMENTARY_SERVICE] = "supplementary service call",
+ [DECT_CALL_CLASS_QA_M] = "QA&M call",
+};
+
+static const char *basic_services[DECT_SERVICE_MAX + 1] = {
+ [DECT_SERVICE_BASIC_SPEECH_DEFAULT] = "basic speech default attributes",
+ [DECT_SERVICE_DECT_GSM_IWP] = "DECT GSM IWP profile",
+ [DECT_SERVICE_UMTS_IWP] = "DECT UMTS IWP",
+ [DECT_SERVICE_LRMS] = "LRMS (E-profile) service",
+ [DECT_SERVICE_GSM_IWP_SMS] = "GSM IWP SMS",
+ [DECT_SERVICE_WIDEBAND_SPEECH] = "Wideband speech",
+ [DECT_SERVICE_OTHER] = "Other",
+};
+
+static void dect_sfmt_dump_basic_service(const struct dect_ie_common *_ie)
+{
+ const struct dect_ie_basic_service *ie = dect_ie_container(ie, _ie);
+
+ dect_debug("basic service:\n\tcall class: %s\n\tservice: %s\n",
+ call_classes[ie->class], basic_services[ie->service]);
+}
+
+static int dect_sfmt_parse_basic_service(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_basic_service *dst = dect_ie_container(dst, *ie);
+
+ dst->class = src->data[1] >> DECT_BASIC_SERVICE_CALL_CLASS_SHIFT;
+ dst->service = src->data[1] & DECT_BASIC_SERVICE_SERVICE_MASK;
+ dect_sfmt_dump_basic_service(*ie);
+ return 0;
+}
+
+static int dect_sfmt_build_basic_service(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie)
+{
+ struct dect_ie_basic_service *src = dect_ie_container(src, ie);
+
+ dst->data[1] = src->class << DECT_BASIC_SERVICE_CALL_CLASS_SHIFT;
+ dst->data[1] |= src->service;
+ return 0;
+}
+
+static int dect_sfmt_parse_single_display(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_display *dst = dect_ie_container(dst, *ie);
+
+ dst->info[0] = src->data[1];
+ dst->len = 1;
+ dect_debug("single display: '%c'\n", dst->info[0]);
+ return 0;
+}
+
+static int dect_sfmt_build_single_display(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *src)
+{
+ struct dect_ie_display *ie = dect_ie_container(ie, src);
+
+ dst->data[1] = ie->info[0];
+ return 0;
+}
+
+static int dect_sfmt_parse_single_keypad(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_keypad *dst = dect_ie_container(dst, *ie);
+
+ dst->info[0] = src->data[1];
+ dst->len = 1;
+ dect_debug("single keypad: '%c'\n", dst->info[0]);
+ return 0;
+}
+
+static int dect_sfmt_parse_release_reason(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_release_reason *dst = dect_ie_container(dst, *ie);
+
+ dst->reason = src->data[1];
+ dect_debug("release reason: %x\n", dst->reason);
+ return 0;
+}
+
+static int dect_sfmt_build_release_reason(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie)
+{
+ struct dect_ie_release_reason *src = dect_ie_container(src, ie);
+
+ dst->data[1] = src->reason;
+ return 0;
+}
+
+static int dect_sfmt_parse_signal(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_signal *dst = dect_ie_container(dst, *ie);
+
+ dst->code = src->data[1];
+ return 0;
+}
+
+static int dect_sfmt_build_signal(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *src)
+{
+ struct dect_ie_signal *ie = dect_ie_container(ie, src);
+
+ dst->data[1] = ie->code;
+ return 0;
+}
+
+static int dect_sfmt_parse_timer_restart(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_timer_restart *dst = dect_ie_container(dst, *ie);
+
+ dst->code = src->data[1];
+ switch (dst->code) {
+ case DECT_TIMER_RESTART:
+ case DECT_TIMER_STOP:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static int dect_sfmt_parse_portable_identity(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_portable_identity *dst = dect_ie_container(dst, *ie);
+ uint8_t len;
+
+ if (src->len < S_VL_IE_PORTABLE_IDENTITY_MIN_SIZE)
+ return -1;
+ if (!(src->data[2] & 0x80))
+ return -1;
+
+ dst->type = src->data[2] & S_VL_IE_PORTABLE_IDENTITY_TYPE_MASK;
+ len = src->data[3] & S_VL_IE_PORTABLE_IDENTITY_LENGTH_MASK;
+
+ switch (dst->type) {
+ case ID_TYPE_IPUI:
+ if (!dect_parse_ipui(&dst->ipui, src->data + 4, len))
+ dect_debug("parsing failed\n");
+ return 0;
+ case ID_TYPE_IPEI:
+ return 0;
+ case ID_TYPE_TPUI:
+ return 0;
+ default:
+ dect_debug("invalid type %u\n", dst->type);
+ return -1;
+ }
+}
+
+static int dect_sfmt_build_portable_identity(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *src)
+{
+ const struct dect_ie_portable_identity *ie = dect_ie_container(ie, src);
+ uint8_t len;
+
+ switch (ie->type) {
+ case ID_TYPE_IPUI:
+ len = dect_build_ipui(&dst->data[4], &ie->ipui);
+ if (len == 0)
+ return -1;
+ break;
+ case ID_TYPE_IPEI:
+ case ID_TYPE_TPUI:
+ return -1;
+ default:
+ return -1;
+ }
+
+ dst->data[3] = 0x80 | len;
+ dst->data[2] = 0x80 | ie->type;
+ dst->len = 9;
+ return 0;
+}
+
+static int dect_sfmt_parse_fixed_identity(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_fixed_identity *dst = dect_ie_container(dst, *ie);
+ uint8_t len, ari_len;
+ uint64_t ari;
+
+ if (src->len < S_VL_IE_FIXED_IDENTITY_MIN_SIZE)
+ return -1;
+ if (!(src->data[2] & 0x80))
+ return -1;
+
+ dst->type = src->data[2] & S_VL_IE_FIXED_IDENTITY_TYPE_MASK;
+ len = src->data[3] & S_VL_IE_FIXED_IDENTITY_LENGTH_MASK;
+
+ ari = __be64_to_cpu(*(__be64 *)&src->data[4]);
+ ari_len = dect_parse_ari(&dst->ari, ari << 1);
+ if (ari_len == 0)
+ return -1;
+
+ switch (dst->type) {
+ case ID_TYPE_ARI:
+ case ID_TYPE_PARK:
+ return ari_len + 1 == len;
+ case ID_TYPE_ARI_RPN:
+ case ID_TYPE_ARI_WRS:
+ return 0;
+ default:
+ dect_debug("invalid type %u\n", dst->type);
+ return -1;
+ }
+}
+
+static int dect_sfmt_build_fixed_identity(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie)
+{
+ struct dect_ie_fixed_identity *src = dect_ie_container(src, ie);
+ uint64_t ari;
+
+ ari = dect_build_ari(&src->ari) >> 1;
+ dst->data[8] = ari >> 24;
+ dst->data[7] = ari >> 32;
+ dst->data[6] = ari >> 40;
+ dst->data[5] = ari >> 48;
+ dst->data[4] = ari >> 56;
+ dst->data[3] = 0x80 | (DECT_ARC_A_LEN + 1);
+ dst->data[2] = 0x80 | src->type;
+ dst->len = 9;
+ return 0;
+}
+
+static int dect_sfmt_parse_progress_indicator(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_progress_indicator *dst = dect_ie_container(dst, *ie);
+
+ dst->location = src->data[2] & DECT_SFMT_IE_PROGRESS_INDICATOR_LOCATION_MASK;
+ dst->progress = src->data[3];
+ return 0;
+}
+
+static int dect_sfmt_build_progress_indicator(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie)
+{
+ struct dect_ie_progress_indicator *src = dect_ie_container(src, ie);
+
+ dst->data[3] = 0x80 | src->progress;
+ dst->data[2] = 0x80 | src->location;
+ dst->len = 4;
+ return 0;
+}
+
+static int dect_sfmt_build_multi_display(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie)
+{
+ struct dect_ie_display *src = dect_ie_container(src, ie);
+
+ memcpy(dst->data + 2, src->info, src->len);
+ dst->len = src->len + 2;
+ return 0;
+}
+
+static int dect_sfmt_parse_multi_keypad(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_keypad *dst = dect_ie_container(dst, *ie);
+
+ dst->len = src->len - 2;
+ memcpy(dst->info, src->data + 2, src->len - 2);
+ dect_debug("multi-keypad: '%.*s'\n", dst->len, dst->info);
+ return 0;
+}
+
+static int dect_sfmt_parse_reject_reason(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_reject_reason *dst = dect_ie_container(dst, *ie);
+
+ dst->reason = src->data[2];
+ dect_debug("reject reason: %x\n", dst->reason);
+ return 0;
+}
+
+static int dect_sfmt_parse_escape_to_proprietary(const struct dect_handle *dh,
+ struct dect_ie_common **ie,
+ const struct dect_sfmt_ie *src)
+{
+ struct dect_ie_escape_to_proprietary *dst = dect_ie_container(dst, *ie);
+ uint8_t dtype;
+
+ dtype = (src->data[2] & DECT_ESC_TO_PROPRIETARY_IE_DESC_TYPE_MASK);
+ if (dtype != DECT_ESC_TO_PROPRIETARY_IE_DESC_EMC)
+ return -1;
+ dst->emc = __be16_to_cpu(*(__be16 *)&src->data[3]);
+ dect_debug("EMC %x\n", dst->emc);
+ return 0;
+}
+
+static const struct dect_ie_handler {
+ const char *name;
+ size_t size;
+ int (*parse)(const struct dect_handle *dh,
+ struct dect_ie_common **dst,
+ const struct dect_sfmt_ie *ie);
+ int (*build)(struct dect_sfmt_ie *dst,
+ const struct dect_ie_common *ie);
+} dect_ie_handlers[256] = {
+ [S_SO_IE_REPEAT_INDICATOR] = {
+ .name = "repeat indicator",
+ .parse = dect_sfmt_parse_repeat_indicator,
+ .build = dect_sfmt_build_repeat_indicator,
+ },
+ [S_SE_IE_SENDING_COMPLETE] = {
+ .name = "sending complete",
+ .size = sizeof(struct dect_ie_sending_complete),
+ .parse = dect_sfmt_parse_empty_single_octet,
+ .build = dect_sfmt_build_empty_single_octet,
+ },
+ [S_SE_IE_DELIMITER_REQUEST] = {
+ .name = "delimiter request",
+ .size = sizeof(struct dect_ie_delimiter_request),
+ .parse = dect_sfmt_parse_empty_single_octet,
+ .build = dect_sfmt_build_empty_single_octet,
+ },
+ [S_SE_IE_USE_TPUI] = {
+ .name = "use TPUI",
+ .size = sizeof(struct dect_ie_use_tpui),
+ .parse = dect_sfmt_parse_empty_single_octet,
+ .build = dect_sfmt_build_empty_single_octet,
+ },
+ [S_DO_IE_BASIC_SERVICE] = {
+ .name = "basic service",
+ .size = sizeof(struct dect_ie_basic_service),
+ .parse = dect_sfmt_parse_basic_service,
+ .build = dect_sfmt_build_basic_service,
+ },
+ [S_DO_IE_RELEASE_REASON] = {
+ .name = "release reason",
+ .size = sizeof(struct dect_ie_release_reason),
+ .parse = dect_sfmt_parse_release_reason,
+ .build = dect_sfmt_build_release_reason,
+ },
+ [S_DO_IE_SIGNAL] = {
+ .name = "signal",
+ .size = sizeof(struct dect_ie_signal),
+ .parse = dect_sfmt_parse_signal,
+ .build = dect_sfmt_build_signal,
+ },
+ [S_DO_IE_TIMER_RESTART] = {
+ .name = "timer restart",
+ .size = sizeof(struct dect_ie_timer_restart),
+ .parse = dect_sfmt_parse_timer_restart,
+ },
+ [S_DO_IE_TEST_HOOK_CONTROL] = {
+ .name = "test hook control",
+ },
+ [S_DO_IE_SINGLE_DISPLAY] = {
+ .name = "single display",
+ .size = sizeof(struct dect_ie_display),
+ .parse = dect_sfmt_parse_single_display,
+ .build = dect_sfmt_build_single_display,
+ },
+ [S_DO_IE_SINGLE_KEYPAD] = {
+ .name = "single keypad",
+ .size = sizeof(struct dect_ie_keypad),
+ .parse = dect_sfmt_parse_single_keypad,
+ },
+ [S_VL_IE_INFO_TYPE] = {
+ .name = "info type",
+ .size = sizeof(struct dect_ie_info_type),
+ },
+ [S_VL_IE_IDENTITY_TYPE] = {
+ .name = "identity type",
+ .size = sizeof(struct dect_ie_identity_type)
+ },
+ [S_VL_IE_PORTABLE_IDENTITY] = {
+ .name = "portable identity",
+ .size = sizeof(struct dect_ie_portable_identity),
+ .parse = dect_sfmt_parse_portable_identity,
+ .build = dect_sfmt_build_portable_identity,
+ },
+ [S_VL_IE_FIXED_IDENTITY] = {
+ .name = "fixed identity",
+ .size = sizeof(struct dect_ie_fixed_identity),
+ .parse = dect_sfmt_parse_fixed_identity,
+ .build = dect_sfmt_build_fixed_identity,
+ },
+ [S_VL_IE_LOCATION_AREA] = {
+ .name = "location area",
+ .size = sizeof(struct dect_ie_location_area),
+ },
+ [S_VL_IE_NWK_ASSIGNED_IDENTITY] = {
+ .name = "NWK assigned identity",
+ .size = sizeof(struct dect_ie_nwk_assigned_identity),
+ },
+ [S_VL_IE_AUTH_TYPE] = {
+ .name = "auth type",
+ .size = sizeof(struct dect_ie_auth_type),
+ },
+ [S_VL_IE_ALLOCATION_TYPE] = {
+ .name = "allocation type",
+ .size = sizeof(struct dect_ie_allocation_type),
+ },
+ [S_VL_IE_RAND] = {
+ .name = "RAND",
+ .size = sizeof(struct dect_ie_rand),
+ },
+ [S_VL_IE_RES] = {
+ .name = "RES",
+ .size = sizeof(struct dect_ie_res),
+ },
+ [S_VL_IE_RS] = {
+ .name = "RS",
+ .size = sizeof(struct dect_ie_rs),
+ },
+ [S_VL_IE_IWU_ATTRIBUTES] = {
+ .name = "IWU attributes",
+ .size = sizeof(struct dect_ie_iwu_attributes),
+ },
+ [S_VL_IE_CALL_ATTRIBUTES] = {
+ .name = "call attributes",
+ .size = sizeof(struct dect_ie_call_attributes),
+ },
+ [S_VL_IE_SERVICE_CHANGE_INFO] = {
+ .name = "service change info",
+ .size = sizeof(struct dect_ie_service_change_info),
+ },
+ [S_VL_IE_CONNECTION_ATTRIBUTES] = {
+ .name = "connection attributes",
+ .size = sizeof(struct dect_ie_connection_attributes),
+ },
+ [S_VL_IE_CIPHER_INFO] = {
+ .name = "cipher info",
+ .size = sizeof(struct dect_ie_cipher_info),
+ },
+ [S_VL_IE_CALL_IDENTITY] = {
+ .name = "call identity",
+ .size = sizeof(struct dect_ie_call_identity),
+ },
+ [S_VL_IE_CONNECTION_IDENTITY] = {
+ .name = "connection identity",
+ .size = sizeof(struct dect_ie_connection_identity),
+ },
+ [S_VL_IE_FACILITY] = {
+ .name = "facility",
+ .size = sizeof(struct dect_ie_facility),
+ },
+ [S_VL_IE_PROGRESS_INDICATOR] = {
+ .name = "progress indicator",
+ .size = sizeof(struct dect_ie_progress_indicator),
+ .parse = dect_sfmt_parse_progress_indicator,
+ .build = dect_sfmt_build_progress_indicator,
+ },
+ [S_VL_IE_MMS_GENERIC_HEADER] = {
+ .name = "MMS generic header",
+ .size = sizeof(struct dect_ie_mms_generic_header),
+ },
+ [S_VL_IE_MMS_OBJECT_HEADER] = {
+ .name = "MMS object header",
+ .size = sizeof(struct dect_ie_mms_object_header),
+ },
+ [S_VL_IE_MMS_EXTENDED_HEADER] = {
+ .name = "MMS extended header",
+ .size = sizeof(struct dect_ie_mms_extended_header),
+ },
+ [S_VL_IE_TIME_DATE] = {
+ .name = "time-date",
+ .size = sizeof(struct dect_ie_time_date),
+ },
+ [S_VL_IE_MULTI_DISPLAY] = {
+ .name = "multi display",
+ .size = sizeof(struct dect_ie_display),
+ .build = dect_sfmt_build_multi_display,
+ },
+ [S_VL_IE_MULTI_KEYPAD] = {
+ .name = "multi keypad",
+ .size = sizeof(struct dect_ie_keypad),
+ .parse = dect_sfmt_parse_multi_keypad,
+ },
+ [S_VL_IE_FEATURE_ACTIVATE] = {
+ .name = "feature activate",
+ .size = sizeof(struct dect_ie_feature_activate),
+ },
+ [S_VL_IE_FEATURE_INDICATE] = {
+ .name = "feature indicate",
+ .size = sizeof(struct dect_ie_feature_indicate),
+ },
+ [S_VL_IE_NETWORK_PARAMETER] = {
+ .name = "network parameter",
+ .size = sizeof(struct dect_ie_network_parameter),
+ },
+ [S_VL_IE_EXT_HO_INDICATOR] = {
+ .name = "ext H/O indicator",
+ .size = sizeof(struct dect_ie_ext_ho_indicator),
+ },
+ [S_VL_IE_ZAP_FIELD] = {
+ .name = "ZAP field",
+ .size = sizeof(struct dect_ie_zap_field),
+ },
+ [S_VL_IE_SERVICE_CLASS] = {
+ .name = "service class",
+ .size = sizeof(struct dect_ie_service_class),
+ },
+ [S_VL_IE_KEY] = {
+ .name = "key",
+ .size = sizeof(struct dect_ie_key),
+ },
+ [S_VL_IE_REJECT_REASON] = {
+ .name = "reject reason",
+ .size = sizeof(struct dect_ie_reject_reason),
+ .parse = dect_sfmt_parse_reject_reason,
+ },
+ [S_VL_IE_SETUP_CAPABILITY] = {
+ .name = "setup capability",
+ .size = sizeof(struct dect_ie_setup_capability),
+ },
+ [S_VL_IE_TERMINAL_CAPABILITY] = {
+ .name = "terminal capability",
+ .size = sizeof(struct dect_ie_terminal_capability),
+ },
+ [S_VL_IE_END_TO_END_COMPATIBILITY] = {
+ .name = "end-to-end compatibility",
+ .size = sizeof(struct dect_ie_end_to_end_compatibility),
+ },
+ [S_VL_IE_RATE_PARAMETERS] = {
+ .name = "rate parameters",
+ .size = sizeof(struct dect_ie_rate_parameters),
+ },
+ [S_VL_IE_TRANSIT_DELAY] = {
+ .name = "transit delay",
+ .size = sizeof(struct dect_ie_transit_delay),
+ },
+ [S_VL_IE_WINDOW_SIZE] = {
+ .name = "window size",
+ .size = sizeof(struct dect_ie_window_size),
+ },
+ [S_VL_IE_CALLING_PARTY_NUMBER] = {
+ .name = "calling party number",
+ .size = sizeof(struct dect_ie_calling_party_number),
+ },
+ [S_VL_IE_CALLING_PARTY_NAME] = {
+ .name = "calling party name",
+ .size = sizeof(struct dect_ie_calling_party_name),
+ },
+ [S_VL_IE_CALLED_PARTY_NUMBER] = {
+ .name = "called party number",
+ .size = sizeof(struct dect_ie_called_party_number),
+ },
+ [S_VL_IE_CALLED_PARTY_SUBADDR] = {
+ .name = "called party subaddress",
+ .size = sizeof(struct dect_ie_called_party_subaddress),
+ },
+ [S_VL_IE_DURATION] = {
+ .name = "duration",
+ .size = sizeof(struct dect_ie_duration),
+ },
+ [S_VL_IE_SEGMENTED_INFO] = {
+ .name = "segmented info",
+ .size = sizeof(struct dect_ie_segmented_info),
+ },
+ [S_VL_IE_ALPHANUMERIC] = {
+ .name = "alphanumeric",
+ .size = sizeof(struct dect_ie_alphanumeric),
+ },
+ [S_VL_IE_IWU_TO_IWU] = {
+ .name = "IWU-to-IWU",
+ .size = sizeof(struct dect_ie_iwu_to_iwu),
+ },
+ [S_VL_IE_MODEL_IDENTIFIER] = {
+ .name = "model identifier",
+ .size = sizeof(struct dect_ie_model_identifier),
+ },
+ [S_VL_IE_IWU_PACKET] = {
+ .name = "IWU-packet",
+ .size = sizeof(struct dect_ie_iwu_packet),
+ },
+ [S_VL_IE_ESCAPE_TO_PROPRIETARY] = {
+ .name = "escape to proprietary",
+ .size = sizeof(struct dect_ie_escape_to_proprietary),
+ .parse = dect_sfmt_parse_escape_to_proprietary,
+ },
+ [S_VL_IE_CODEC_LIST] = {
+ .name = "codec list",
+ .size = sizeof(struct dect_ie_codec_list),
+ },
+ [S_VL_IE_EVENTS_NOTIFICATION] = {
+ .name = "events notification",
+ .size = sizeof(struct dect_ie_events_notification),
+ },
+ [S_VL_IE_CALL_INFORMATION] = {
+ .name = "call information",
+ .size = sizeof(struct dect_ie_call_information),
+ },
+ [S_VL_IE_ESCAPE_FOR_EXTENSION] = {
+ .name = "escape for extension",
+ },
+};
+
+static struct dect_ie_common **
+dect_next_ie(const struct dect_sfmt_ie_desc *desc, struct dect_ie_common **ie)
+{
+ if (desc->type == S_SO_IE_REPEAT_INDICATOR)
+ return ((void *)ie) + sizeof(struct dect_ie_repeat_indicator);
+ else if (!(desc->flags & DECT_SFMT_IE_REPEAT))
+ return ie + 1;
+ else
+ return ie;
+}
+
+static void dect_msg_ie_init(const struct dect_sfmt_ie_desc *desc,
+ struct dect_ie_common **ie)
+{
+ struct dect_ie_repeat_indicator *rep;
+
+ if (desc->flags & DECT_SFMT_IE_END)
+ return;
+
+ //dect_debug("init message IE %p: <%s>\n",
+ // ie, dect_ie_handlers[desc->type].name);
+
+ if (desc->type == S_SO_IE_REPEAT_INDICATOR) {
+ rep = dect_ie_container(rep, (struct dect_ie_common *)ie);
+ init_list_head(&rep->list);
+ } else if (!(desc->flags & DECT_SFMT_IE_REPEAT))
+ *ie = NULL;
+}
+
+static int dect_parse_sfmt_ie_header(struct dect_sfmt_ie *ie,
+ const struct dect_msg_buf *mb)
+{
+ uint8_t val;
+
+ if (mb->len < 1)
+ return -1;
+
+ ie->id = mb->data[0] & DECT_SFMT_IE_FIXED_LEN;
+ if (ie->id & DECT_SFMT_IE_FIXED_LEN) {
+ ie->id |= (mb->data[0] & DECT_SFMT_IE_FIXED_ID_MASK);
+ val = (mb->data[0] & DECT_SFMT_IE_FIXED_VAL_MASK);
+ if (ie->id != S_SO_IE_DOUBLE_OCTET_ELEMENT) {
+ ie->len = 1;
+ if (ie->id == S_SO_IE_EXT_PREFIX)
+ ie->id |= val;
+ } else {
+ if (mb->len < 2)
+ return -1;
+ ie->id |= val;
+ ie->len = 2;
+ }
+ } else {
+ if (mb->len < 2U || mb->len < 2U + mb->data[1])
+ return -1;
+ ie->id = mb->data[0];
+ ie->len = mb->data[1] + 2;
+ }
+ ie->data = mb->data;
+
+ dect_debug("found IE: <%s> (%x) len: %u\n", dect_ie_handlers[ie->id].name,
+ ie->id, ie->len);
+ return 0;
+}
+
+static int dect_build_sfmt_ie_header(struct dect_sfmt_ie *dst, uint8_t id)
+{
+ if (id & DECT_SFMT_IE_FIXED_LEN) {
+ dst->data[0] |= id;
+ if ((id & DECT_SFMT_IE_FIXED_ID_MASK) !=
+ (S_SO_IE_DOUBLE_OCTET_ELEMENT & DECT_SFMT_IE_FIXED_ID_MASK))
+ dst->len = 1;
+ else
+ dst->len = 2;
+ } else {
+ if (dst->len == 2)
+ dst->len = 0;
+ else {
+ assert(dst->len > 2);
+ dst->data[1] = dst->len - 2;
+ dst->data[0] = id;
+ }
+ }
+ return 0;
+}
+
+static int dect_parse_sfmt_ie(const struct dect_handle *dh,
+ const struct dect_sfmt_ie_desc *desc,
+ struct dect_ie_common **dst,
+ struct dect_sfmt_ie *ie)
+{
+ const struct dect_ie_handler *ieh;
+ int err = -1;
+
+ ieh = &dect_ie_handlers[ie->id];
+ if (ieh->parse == NULL)
+ goto err1;
+
+ if (ieh->size > 0) {
+ *dst = dect_ie_alloc(dh, ieh->size);
+ if (*dst == NULL)
+ goto err1;
+ }
+
+ dect_debug("parse: IE <%s> dst %p len %u\n", ieh->name, *dst, ie->len);
+ err = ieh->parse(dh, dst, ie);
+ if (err < 0)
+ goto err2;
+ return 0;
+
+err2:
+ dect_free(dh, *dst);
+ *dst = NULL;
+err1:
+ dect_debug("smsg: IE parsing error\n");
+ return err;
+}
+
+enum dect_sfmt_error dect_parse_sfmt_msg(const struct dect_handle *dh,
+ const struct dect_sfmt_ie_desc *desc,
+ struct dect_msg_common *_dst,
+ struct dect_msg_buf *mb)
+{
+ struct dect_ie_common **dst = &_dst->ie[0];
+ struct dect_sfmt_ie _ie[2], *ie;
+ uint8_t idx = 0;
+
+ dect_msg_ie_init(desc, dst);
+ while (mb->len > 0) {
+ /* Parse the next information element header */
+ ie = &_ie[idx++ % array_size(_ie)];;
+ if (dect_parse_sfmt_ie_header(ie, mb) < 0)
+ return -1;
+
+ /* Treat empty variable length IEs as absent */
+ if (!(ie->id & DECT_SFMT_IE_FIXED_LEN) && ie->len == 2)
+ goto next;
+
+ /* Locate a matching member in the description and apply
+ * policy checks. */
+ while (1) {
+ if (desc->flags & DECT_SFMT_IE_END)
+ goto out;
+
+ switch (desc->f_p) {
+ case DECT_SFMT_IE_MANDATORY:
+ if (desc->type == ie->id)
+ goto found;
+ return DECT_SFMT_MANDATORY_IE_MISSING;
+ case DECT_SFMT_IE_NONE:
+ if (desc->type == ie->id)
+ return -1;
+ break;
+ case DECT_SFMT_IE_OPTIONAL:
+ if (desc->type == ie->id)
+ goto found;
+ if (desc->type == S_DO_IE_SINGLE_DISPLAY &&
+ ie->id == S_VL_IE_MULTI_DISPLAY)
+ goto found;
+ if (desc->type == S_DO_IE_SINGLE_KEYPAD &&
+ ie->id == S_VL_IE_MULTI_KEYPAD)
+ goto found;
+ break;
+ }
+
+ dst = dect_next_ie(desc, dst);
+ desc++;
+ dect_msg_ie_init(desc, dst);
+ }
+found:
+ /* Ignore corrupt optional IEs */
+ if (dect_parse_sfmt_ie(dh, desc, dst, ie) < 0 &&
+ desc->f_p == DECT_SFMT_IE_MANDATORY)
+ return DECT_SFMT_MANDATORY_IE_ERROR;
+
+next:
+ dect_mbuf_pull(mb, ie->len);
+
+ dst = dect_next_ie(desc, dst);
+ desc++;
+ dect_msg_ie_init(desc, dst);
+ }
+out:
+ while (!(desc->flags & DECT_SFMT_IE_END)) {
+ dect_debug("clear missing IE: <%s>\n", dect_ie_handlers[desc->type].name);
+ if (desc->f_p == DECT_SFMT_IE_MANDATORY)
+ return DECT_SFMT_MANDATORY_IE_MISSING;
+ dst = dect_next_ie(desc, dst);
+ desc++;
+ dect_msg_ie_init(desc, dst);
+ }
+
+ return DECT_SFMT_OK;
+}
+
+static enum dect_sfmt_error
+dect_build_sfmt_ie(const struct dect_handle *dh,
+ const struct dect_sfmt_ie_desc *desc,
+ struct dect_msg_buf *mb,
+ struct dect_ie_common *ie)
+{
+ const struct dect_ie_handler *ieh;
+ uint16_t type = desc->type;
+ struct dect_sfmt_ie dst;
+ enum dect_sfmt_error err = 0;
+
+ if (desc->p_f == DECT_SFMT_IE_NONE)
+ return DECT_SFMT_INVALID_IE;
+
+ if (type == S_DO_IE_SINGLE_DISPLAY) {
+ struct dect_ie_display *display = dect_ie_container(display, ie);
+ if (display->len > 1)
+ type = S_VL_IE_MULTI_DISPLAY;
+ }
+ if (type == S_DO_IE_SINGLE_KEYPAD) {
+ struct dect_ie_keypad *keypad = dect_ie_container(keypad, ie);
+ if (keypad->len > 1)
+ type = S_VL_IE_MULTI_KEYPAD;
+ }
+
+ ieh = &dect_ie_handlers[type];
+ if (ieh->build == NULL)
+ goto err1;
+
+ dect_debug("build IE: %s %p\n", ieh->name, ie);
+ dst.data = mb->data + mb->len;
+ dst.len = 0;
+ err = ieh->build(&dst, ie);
+ if (err < 0)
+ goto err1;
+
+ dect_build_sfmt_ie_header(&dst, type);
+ mb->len += dst.len;
+ return 0;
+
+err1:
+ return err;
+}
+
+enum dect_sfmt_error dect_build_sfmt_msg(const struct dect_handle *dh,
+ const struct dect_sfmt_ie_desc *desc,
+ const struct dect_msg_common *_src,
+ struct dect_msg_buf *mb)
+{
+ struct dect_ie_common * const *src = &_src->ie[0], **next, *rsrc;
+ struct dect_ie_repeat_indicator *rep;
+ enum dect_sfmt_error err;
+
+ while (!(desc->flags & DECT_SFMT_IE_END)) {
+ next = dect_next_ie(desc, (struct dect_ie_common **)src);
+
+ if (desc->type == S_SO_IE_REPEAT_INDICATOR) {
+ rep = (struct dect_ie_repeat_indicator *)src;
+ if (rep->list.next == NULL || list_empty(&rep->list)) {
+ desc++;
+ goto next;
+ }
+
+ if (rep->list.next->next != &rep->list)
+ err = dect_build_sfmt_ie(dh, desc, mb, &rep->common);
+ desc++;
+
+ assert(desc->flags & DECT_SFMT_IE_REPEAT);
+ assert(!list_empty(&rep->list));
+ list_for_each_entry(rsrc, &rep->list, list) {
+ dect_debug("list elem %p next %p\n", rsrc, rsrc->list.next);
+ err = dect_build_sfmt_ie(dh, desc, mb, rsrc);
+ }
+ } else {
+ if (*src == NULL)
+ goto next;
+ err = dect_build_sfmt_ie(dh, desc, mb, *src);
+ }
+next:
+ src = next;
+ desc++;
+ }
+
+ return DECT_SFMT_OK;
+}
+
+void dect_msg_free(const struct dect_handle *dh,
+ const struct dect_sfmt_ie_desc *desc,
+ struct dect_msg_common *msg)
+{
+ struct dect_ie_common **ie = &msg->ie[0], **next;
+
+ while (!(desc->flags & DECT_SFMT_IE_END)) {
+ next = dect_next_ie(desc, ie);
+
+ //dect_debug("free %s %p\n", dect_ie_handlers[desc->type].name, ie);
+ if (desc->type == S_SO_IE_REPEAT_INDICATOR)
+ desc++;
+ else if (*ie != NULL && --(*ie)->refcnt == 0)
+ dect_free(dh, *ie);
+
+ ie = next;
+ desc++;
+ }
+}
diff --git a/src/ss.c b/src/ss.c
new file mode 100644
index 0000000..3fcaee0
--- /dev/null
+++ b/src/ss.c
@@ -0,0 +1,49 @@
+/*
+ * DECT Supplementary Services (SS)
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/dect.h>
+
+#include <libdect.h>
+#include <utils.h>
+#include <s_fmt.h>
+#include <lce.h>
+#include <ss.h>
+
+
+static const struct dect_sfmt_ie_desc ciss_facility_msg_desc[] = {
+ DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_DO_IE_SINGLE_KEYPAD, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_ACTIVATE, IE_NONE, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
+ DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
+ DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_TIME_DATE, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_EVENTS_NOTIFICATION, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE(S_VL_IE_CALL_INFORMATION, IE_OPTIONAL, IE_OPTIONAL, 0),
+ DECT_SFMT_IE_END_MSG
+};
+
+void dect_clss_rcv(struct dect_handle *dh, struct dect_msg_buf *mb)
+{
+ struct dect_ciss_facility_msg msg;
+
+ if (mb->type != CISS_FACILITY)
+ return;
+
+ if (dect_parse_sfmt_msg(dh, ciss_facility_msg_desc, &msg.common, mb) < 0)
+ return;
+}
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..e318fcb
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,142 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <libdect.h>
+#include <utils.h>
+
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK O_NONBLOCK
+#endif
+
+void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ if (i % 16 == 0)
+ dect_debug("%s%s: ", i ? "\n" : "", prefix);
+ dect_debug("%.2x ", buf[i]);
+ }
+ dect_debug("\n\n");
+}
+
+void *dect_malloc(const struct dect_handle *dh, size_t size)
+{
+ return dh->ops->malloc(size);
+}
+
+void *dect_zalloc(const struct dect_handle *dh, size_t size)
+{
+ void *ptr;
+
+ ptr = dect_malloc(dh, size);
+ if (ptr != NULL)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void dect_free(const struct dect_handle *dh, void *ptr)
+{
+ dh->ops->free(ptr);
+}
+
+struct dect_timer *dect_alloc_timer(const struct dect_handle *dh)
+{
+ return dect_malloc(dh, sizeof(struct dect_timer) +
+ dh->ops->event_ops->timer_priv_size);
+}
+
+void dect_start_timer(const struct dect_handle *dh,
+ struct dect_timer *timer, unsigned int timeout)
+{
+ struct timeval tv = {
+ .tv_sec = timeout,
+ };
+
+ dh->ops->event_ops->start_timer(dh, timer, &tv);
+}
+
+void dect_stop_timer(const struct dect_handle *dh, struct dect_timer *timer)
+{
+ dh->ops->event_ops->stop_timer(dh, timer);
+}
+
+struct dect_fd *dect_alloc_fd(const struct dect_handle *dh)
+{
+ struct dect_fd *dfd;
+
+ dfd = dect_malloc(dh, sizeof(struct dect_fd) +
+ dh->ops->event_ops->fd_priv_size);
+ if (dfd == NULL)
+ return NULL;
+ dfd->fd = -1;
+ return dfd;
+}
+
+int dect_register_fd(const struct dect_handle *dh, struct dect_fd *dfd,
+ uint32_t events)
+{
+ return dh->ops->event_ops->register_fd(dh, dfd, events);
+}
+
+void dect_unregister_fd(const struct dect_handle *dh, struct dect_fd *dfd)
+{
+ dh->ops->event_ops->unregister_fd(dh, dfd);
+}
+
+void dect_close(const struct dect_handle *dh, struct dect_fd *dfd)
+{
+ if (dfd->fd >= 0)
+ close(dfd->fd);
+ dect_free(dh, dfd);
+}
+
+struct dect_fd *dect_socket(const struct dect_handle *dh, int type, int protocol)
+{
+ struct dect_fd *dfd;
+
+ dfd = dect_alloc_fd(dh);
+ if (dfd == NULL)
+ goto err1;
+
+ dfd->fd = socket(AF_DECT, type | SOCK_NONBLOCK, protocol);
+ if (dfd->fd < 0)
+ goto err2;
+
+ return dfd;
+
+err2:
+ dect_close(dh, dfd);
+err1:
+ return NULL;
+}
+
+struct dect_fd *dect_accept(const struct dect_handle *dh,
+ const struct dect_fd *dfd,
+ struct sockaddr *addr, socklen_t len)
+{
+ struct dect_fd *nfd;
+
+ nfd = dect_alloc_fd(dh);
+ if (nfd == NULL)
+ goto err1;
+
+ nfd->fd = accept(dfd->fd, addr, &len);
+ if (nfd->fd < 0)
+ goto err2;
+ if (fcntl(nfd->fd, F_SETFL, O_NONBLOCK) < 0)
+ goto err2;
+
+ return nfd;
+
+err2:
+ dect_close(dh, nfd);
+err1:
+ return NULL;
+}