summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore18
-rw-r--r--Makefile.defs.in42
-rw-r--r--Makefile.in5
-rw-r--r--Makefile.rules.in108
-rwxr-xr-xautogen.sh4
-rw-r--r--configure.ac74
-rw-r--r--doc/Doxyfile.in1417
-rw-r--r--doc/Makefile.in4
-rw-r--r--example/.gitignore1
-rw-r--r--example/Makefile.in8
-rw-r--r--example/audio.c95
-rw-r--r--example/common.h23
-rw-r--r--example/event_ops.c115
-rwxr-xr-xexample/mmbin0 -> 39435 bytes
-rw-r--r--example/mm.c74
-rw-r--r--example/test.c294
-rw-r--r--include/Makefile.in3
-rw-r--r--include/b_fmt.h48
-rw-r--r--include/cc.h333
-rw-r--r--include/coms.h15
-rw-r--r--include/dect/cc.h246
-rw-r--r--include/dect/identities.h169
-rw-r--r--include/dect/ie.h767
-rw-r--r--include/dect/keypad.h15
-rw-r--r--include/dect/libdect.h134
-rw-r--r--include/dect/mm.h38
-rw-r--r--include/dect/terminal.h70
-rw-r--r--include/dect/utils.h8
-rw-r--r--include/identities.h121
-rw-r--r--include/lce.h197
-rw-r--r--include/libdect.h35
-rw-r--r--include/linux/dect.h76
-rw-r--r--include/linux/socket.h306
-rw-r--r--include/list.h625
-rw-r--r--include/mm.h167
-rw-r--r--include/netlink.h7
-rw-r--r--include/s_fmt.h377
-rw-r--r--include/ss.h70
-rw-r--r--include/utils.h70
-rwxr-xr-xinstall-sh269
-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
62 files changed, 12248 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d26b395
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+# Dependency and object files
+.*.d
+*.o
+
+# Generated by autoconf/configure
+Makefile
+Makefile.defs
+Makefile.rules
+config.h
+config.h.in
+config.h.in~
+config.log
+config.status
+configure
+autom4te.cache
+
+# Debian package build temporary files
+build-stamp
diff --git a/Makefile.defs.in b/Makefile.defs.in
new file mode 100644
index 0000000..2d0e900
--- /dev/null
+++ b/Makefile.defs.in
@@ -0,0 +1,42 @@
+DEBUG = @CONFIG_DEBUG@
+CC = @CC@
+CPP = @CPP@
+LEX = @LEX@
+YACC = @YACC@
+MKDIR_P = @MKDIR_P@
+LN_S = @LN_S@
+INSTALL = @INSTALL@
+DOXYGEN = doxygen
+
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+sysconfdir = @sysconfdir@
+datarootdir = @datarootdir@
+mandir = @mandir@
+docdir = @docdir@
+pdfdir = @pdfdir@
+confdir = @sysconfdir@/dect
+
+LDFLAGS += @LDFLAGS@
+LDFLAGS += @LIBS@
+
+CPPFLAGS += @CPPFLAGS@
+
+CFLAGS += @CFLAGS@ @DEFS@
+CFLAGS += -include config.h -I include
+CFLAGS += -fno-strict-aliasing
+
+CFLAGS += -Wall -Werror
+CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
+CFLAGS += -Wdeclaration-after-statement -Wsign-compare -Winit-self
+CFLAGS += -Wformat-nonliteral -Wformat-security -Wmissing-format-attribute
+CFLAGS += -Wcast-align -Wundef -Wbad-function-cast # -Wshadow
+CFLAGS += -Waggregate-return -Wunused -Wwrite-strings
+
+ifeq ($(DEBUG),y)
+CFLAGS += -g -DDEBUG
+endif
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..9c60885
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,5 @@
+SUBDIRS += include
+SUBDIRS += src
+SUBDIRS += example
+
+include Makefile.rules
diff --git a/Makefile.rules.in b/Makefile.rules.in
new file mode 100644
index 0000000..6165393
--- /dev/null
+++ b/Makefile.rules.in
@@ -0,0 +1,108 @@
+include Makefile.defs
+
+makedeps += $(SUBDIR)Makefile
+makedeps += Makefile
+makedeps += Makefile.defs
+makedeps += Makefile.rules
+
+configure: configure.ac
+ sh autogen.sh
+
+%: %.in configure
+ sh configure
+
+%.o: %.c $(makedeps)
+ @echo -e " CC\t\t$<"
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+.%.d: %.c $(makedeps)
+ @echo -e " DEP\t\t$<"
+ $(RM) $@
+ $(CC) -M $(CFLAGS) $< | sed 's,$(*F)\.o[ :]*,$*.o $@ : ,g' > $@
+
+%.c %.h: %.y $(makedeps)
+ @echo -e " YACC\t\t$<"
+ $(YACC) $(YACCFLAGS) -d -o $@ $<
+
+%.c %.h: %.l $(makedeps)
+ @echo -e " LEX\t\t$<"
+ $(LEX) -t --header-file=$(<:.l=.h) $< > $@
+
+%.8: %.xml $(makedeps)
+ @echo -e " MAN\t\t$<"
+ docbook2x-man $<
+
+%.pdf: %.xml $(makedeps)
+ @echo -e " PDF\t\t$<"
+ db2pdf $<
+
+define generic_template
+$(1)-obj := $$(patsubst %,$(SUBDIR)%,$$($(1)-obj))
+depfiles := $$(patsubst $(SUBDIR)%.o,$(SUBDIR).%.d,$$($(1)-obj))
+
+.PHONY: $(1)-clean
+$(1)-clean:
+ @echo -e " CLEAN\t\t$(1)"
+ $$(RM) $$($(1)-obj) $$(depfiles) $$($(1)-extra-clean-files) $(1)
+clean_targets += $(1)-clean
+
+.PHONY: $(1)-install
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $$(depfiles)
+endif
+endef
+
+define program_template
+$(eval $(call generic_template,$(1)))
+
+$(SUBDIR)$(1): $$($(1)-extra-targets) $$($(1)-obj)
+ @echo -e " LD\t\t$$@"
+ $$(CC) $$($(1)-obj) $$(LDFLAGS) -o $$@
+all_targets += $(SUBDIR)$(1)
+
+$(1)-install:
+ @echo -e " INSTALL\t$1"
+ $(MKDIR_P) $$(DESTDIR)/$$($(1)-destdir)
+ $(INSTALL) -m 755 -o root -g root $(SUBDIR)$(1) \
+ $$(DESTDIR)/$$($(1)-destdir)/$(1)
+install_targets += $(1)-install
+endef
+
+define library_template
+$(eval $(call generic_template,$(1)))
+
+$(SUBDIR)lib$(1).so: $$($(1)-extra-targets) $$($(1)-obj)
+ @echo -e " LD\t\t$$@"
+ $$(CC) -shared -Wl,-soname,lib$(1).so.0 $$($(1)-obj) $$(LDFLAGS) -o $$@
+all_targets += $(SUBDIR)lib$(1).so
+
+$(1)-install:
+ @echo -e " INSTALL\t$1"
+ $(MKDIR_P) $$(DESTDIR)/$$($(1)-destdir)
+ $(INSTALL) -m 755 -o root -g root $(SUBDIR)lib$(1).so \
+ $$(DESTDIR)/$$($(1)-destdir)/lib$(1).so.$(PACKAGE_VERSION)
+ $(LN_S) -f lib$(1).so.$(PACKAGE_VERSION) \
+ $(DESTDIR)/$$($(1)-destdir)/lib$(1).so.0
+ $(LN_S) -f lib$(1).so.$(PACKAGE_VERSION) \
+ $(DESTDIR)/$$($(1)-destdir)/lib$(1).so
+install_targets += $(1)-install
+endef
+
+ifneq ($(SUBDIR),)
+include $(SUBDIR)/Makefile
+$(foreach prog,$(PROGRAMS),$(eval $(call program_template,$(prog))))
+$(foreach lib,$(LIBS),$(eval $(call library_template,$(lib))))
+endif
+
+.DEFAULT_GOAL := all
+
+.PHONY: all clean install
+all: $(SUBDIRS) $(all_targets)
+clean: $(SUBDIRS) $(clean_targets)
+install: all $(SUBDIRS) $(install_targets)
+
+.PHONY: $(SUBDIRS)
+$(SUBDIRS):
+ @echo -e " SUBDIR\t$@/"
+ @$(MAKE) -s -f Makefile.rules $(MAKECMDGOALS) SUBDIR="$@/"
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..7d2e816
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,4 @@
+#! /bin/sh
+
+autoreconf -fi;
+rm -Rf autom4te*.cache config.h.in~
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4678d3a
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,74 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.61)
+
+AC_COPYRIGHT([Copyright (c) 2008 Patrick McHardy <kaber@trash.net>])
+AC_INIT([libdect], [0.0.1], [kaber@trash.net])
+AC_DEFINE([RELEASE_NAME], ["libdect"], [Release name])
+
+AC_CONFIG_SRCDIR([src/s_msg.c])
+AC_CONFIG_HEADER([config.h])
+
+AC_DEFINE([_GNU_SOURCE], [], [Enable various GNU extensions])
+AC_DEFINE([_STDC_FORMAT_MACROS], [], [printf-style format macros])
+
+AC_ARG_ENABLE([debug],
+ AS_HELP_STRING([--enable-debug], [Enable debugging]),
+ [CONFIG_DEBUG="$(echo $enableval | cut -b1)"],
+ [CONFIG_DEBUG="y"])
+AC_SUBST([CONFIG_DEBUG])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_MKDIR_P
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+# Checks for libraries.
+AC_CHECK_LIB([nl], [nl_socket_alloc], ,
+ AC_MSG_ERROR([No suitable version of libnl found]))
+
+AC_CHECK_LIB([nl-dect], [nl_dect_cluster_alloc], ,
+ AC_MSG_ERROR([No suitable version of libnl-dect found]))
+
+AC_CHECK_LIB([event], [event_init], ,
+ AC_MSG_ERROR([No suitable version of libevent found]))
+
+AC_CHECK_LIB([SDL], [SDL_OpenAudio], ,
+ AC_MSG_ERROR([No suitable version of libsdl found]))
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_ASSERT
+AC_CHECK_HEADERS([fcntl.h inttypes.h libintl.h limits.h malloc.h \
+ stddef.h stdint.h stdlib.h string.h unistd.h], ,
+ AC_MSG_ERROR([Header file not found]))
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_TYPE_UID_T
+AC_TYPE_INT8_T
+AC_TYPE_INT16_T
+AC_TYPE_INT32_T
+AC_TYPE_INT64_T
+AC_TYPE_UINT8_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT64_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([memmove memset strchr strdup strerror strtoull])
+
+AC_CONFIG_FILES([Makefile Makefile.defs Makefile.rules])
+AC_CONFIG_FILES([include/Makefile])
+AC_CONFIG_FILES([src/Makefile])
+AC_CONFIG_FILES([example/Makefile])
+AC_CONFIG_FILES([doc/Makefile doc/Doxyfile])
+AC_OUTPUT
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..2f94af0
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,1417 @@
+# Doxyfile 1.5.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = libdect
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hiererachy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = NONE
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..000c9d5
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,4 @@
+all: doxygen
+
+doxygen:
+ $(DOXYGEN) $(SUBDIR)Doxyfile
diff --git a/example/.gitignore b/example/.gitignore
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/example/.gitignore
@@ -0,0 +1 @@
+test
diff --git a/example/Makefile.in b/example/Makefile.in
new file mode 100644
index 0000000..da989a3
--- /dev/null
+++ b/example/Makefile.in
@@ -0,0 +1,8 @@
+LDFLAGS += -Lsrc -ldect
+PROGRAMS += test
+
+test-destdir := usr/bin
+
+test-obj += event_ops.o
+test-obj += audio.o
+test-obj += test.o
diff --git a/example/audio.c b/example/audio.c
new file mode 100644
index 0000000..3dfe9cb
--- /dev/null
+++ b/example/audio.c
@@ -0,0 +1,95 @@
+#include <SDL/SDL.h>
+#include <SDL/SDL_audio.h>
+#include "common.h"
+
+void dect_audio_queue(struct dect_audio_handle *ah, struct dect_msg_buf *mb)
+{
+ SDL_LockAudio();
+ list_add_tail(&mb->list, &ah->queue);
+ SDL_UnlockAudio();
+}
+
+static void dect_decode_g721(struct g72x_state *codec,
+ int16_t *dst, const uint8_t *src,
+ unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len * 2; i += 2) {
+ dst[i + 0] = g721_decoder(src[i / 2] >> 4,
+ AUDIO_ENCODING_LINEAR, codec);
+ dst[i + 1] = g721_decoder(src[i / 2] & 0x0f,
+ AUDIO_ENCODING_LINEAR, codec);
+ }
+}
+
+static void dect_audio_dequeue(void *data, uint8_t *stream, int len)
+{
+ struct dect_audio_handle *ah = data;
+ struct dect_msg_buf *mb;
+ int copy;
+
+ len /= 4;
+ while (1) {
+ if (list_empty(&ah->queue))
+ goto underrun;
+ mb = list_first_entry(&ah->queue, struct dect_msg_buf, list);
+ copy = mb->len;
+ if (copy > len)
+ copy = len;
+
+ dect_decode_g721(&ah->codec, (int16_t *)stream, mb->data, copy);
+ dect_mbuf_pull(mb, copy);
+ if (mb->len == 0) {
+ list_del(&mb->list);
+ free(mb);
+ }
+
+ len -= copy;
+ if (len == 0)
+ return;
+ stream += 4 * copy;
+ }
+
+underrun:
+ printf("audio underrun, missing %u bytes\n", len * 4);
+ memset(stream, 0, len * 4);
+}
+
+struct dect_audio_handle *dect_audio_open(void)
+{
+ struct dect_audio_handle *ah;
+ SDL_AudioSpec spec = {
+ .freq = 8000,
+ .format = AUDIO_S16SYS,
+ .channels = 1,
+ .samples = 512,
+ .callback = dect_audio_dequeue,
+ };
+
+ ah = malloc(sizeof(*ah));
+ if (ah == NULL)
+ goto err1;
+ init_list_head(&ah->queue);
+ g72x_init_state(&ah->codec);
+
+ spec.userdata = ah;
+ if (SDL_OpenAudio(&spec, NULL) < 0)
+ goto err2;
+ SDL_PauseAudio(0);
+
+ return ah;
+
+err2:
+ free(ah);
+err1:
+ return NULL;
+}
+
+static void __init dect_audio_init(void)
+{
+ if (SDL_Init(SDL_INIT_AUDIO) < 0) {
+ fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
+ exit(1);
+ }
+}
diff --git a/example/common.h b/example/common.h
new file mode 100644
index 0000000..cb73ec9
--- /dev/null
+++ b/example/common.h
@@ -0,0 +1,23 @@
+#ifndef _DECT_TEST_COMMON_H
+#define _DECT_TEST_COMMON_H
+
+#include <libdect.h>
+#include <utils.h>
+#include <list.h>
+
+extern struct dect_handle *dh;
+extern int dect_event_ops_init(struct dect_ops *ops);
+extern void dect_event_loop(void);
+extern void dect_event_ops_cleanup(void);
+
+#include "../src/ccitt-adpcm/g72x.h"
+
+struct dect_audio_handle {
+ struct g72x_state codec;
+ struct list_head queue;
+};
+
+extern struct dect_audio_handle *dect_audio_open(void);
+extern void dect_audio_queue(struct dect_audio_handle *ah, struct dect_msg_buf *mb);
+
+#endif /* _DECT_TEST_COMMON_H */
diff --git a/example/event_ops.c b/example/event_ops.c
new file mode 100644
index 0000000..2d1f586
--- /dev/null
+++ b/example/event_ops.c
@@ -0,0 +1,115 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <event.h>
+
+#include <libdect.h>
+#include "common.h"
+
+struct dect_handle *dh;
+
+static void event_callback(int fd, short mask, void *data)
+{
+ struct dect_fd *dfd = data;
+ uint32_t events;
+
+ events = 0;
+ if (mask & EV_READ)
+ events |= DECT_FD_READ;
+ if (mask & EV_WRITE)
+ events |= DECT_FD_WRITE;
+
+ dfd->callback(dh, dfd, events);
+}
+
+static int register_fd(const struct dect_handle *dh, struct dect_fd *dfd,
+ uint32_t events)
+{
+ struct event *ev = (struct event *)dfd->priv;
+ unsigned short mask;
+
+ mask = EV_PERSIST;
+ if (events & DECT_FD_READ)
+ mask |= EV_READ;
+ if (events & DECT_FD_WRITE)
+ mask |= EV_WRITE;
+
+ event_set(ev, dfd->fd, mask, event_callback, dfd);
+ event_add(ev, NULL);
+ return 0;
+}
+
+static void unregister_fd(const struct dect_handle *dh, struct dect_fd *dfd)
+{
+ struct event *ev = (struct event *)dfd->priv;
+
+ event_del(ev);
+}
+
+static void timer_expire(int fd, short mask, void *data)
+{
+ struct dect_timer *timer = data;
+
+ timer->callback(dh, timer);
+}
+
+static void start_timer(const struct dect_handle *dh,
+ struct dect_timer *timer,
+ const struct timeval *tv)
+{
+ struct event *ev = (struct event *)timer->priv;
+
+ evtimer_set(ev, timer_expire, timer);
+ evtimer_add(ev, (struct timeval *)tv);
+}
+
+static void stop_timer(const struct dect_handle *dh, struct dect_timer *timer)
+{
+ struct event *ev = (struct event *)timer->priv;
+
+ evtimer_del(ev);
+}
+
+static const struct dect_event_ops dect_event_ops = {
+ .fd_priv_size = sizeof(struct event),
+ .register_fd = register_fd,
+ .unregister_fd = unregister_fd,
+ .timer_priv_size = sizeof(struct event),
+ .start_timer = start_timer,
+ .stop_timer = stop_timer
+};
+
+static struct event_base *ev_base;
+static struct event sig_event;
+static bool sigint;
+
+static void sig_callback(int fd, short event, void *data)
+{
+ sigint = true;
+}
+
+int dect_event_ops_init(struct dect_ops *ops)
+{
+
+ ev_base = event_init();
+ if (ev_base == NULL)
+ return -1;
+ ops->event_ops = &dect_event_ops;
+
+ signal_set(&sig_event, SIGINT, sig_callback, NULL);
+ signal_add(&sig_event, NULL);
+ return 0;
+}
+
+void dect_event_loop(void)
+{
+ while (!sigint)
+ event_loop(EVLOOP_ONCE);
+ signal_del(&sig_event);
+}
+
+void dect_event_ops_cleanup(void)
+{
+ event_base_free(ev_base);
+}
diff --git a/example/mm b/example/mm
new file mode 100755
index 0000000..bde150d
--- /dev/null
+++ b/example/mm
Binary files differ
diff --git a/example/mm.c b/example/mm.c
new file mode 100644
index 0000000..af71011
--- /dev/null
+++ b/example/mm.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dect/libdect.h>
+#include "common.h"
+
+enum phones { PHONE1, PHONE2, PHONE3, };
+static const struct dect_ipui ipuis[] = {
+ [PHONE1] = {
+ .put = DECT_IPUI_N,
+ .pun.n.ipei = {
+ .emc = 0x08ae,
+ .psn = 0x83d1e,
+ },
+ },
+ [PHONE2] = {
+ .put = DECT_IPUI_N,
+ .pun.n.ipei = {
+ .emc = 0x08ae,
+ .psn = 0x8969f,
+ },
+ },
+ [PHONE3] = {
+ .put = DECT_IPUI_N,
+ .pun.n.ipei = {
+ .emc = 0x08ae,
+ .psn = 0x5b9a0,
+ },
+ },
+};
+
+static const struct dect_mm_ops mm_ops = {
+ .mm_access_rights_ind = 0,
+ .mm_access_rights_cfm = 0,
+};
+
+static int mm_access_rights_request(struct dect_handle *dh)
+{
+ struct dect_ie_portable_identity portable_identity;
+ struct dect_mm_access_rights_param param = {
+ .portable_identity = &portable_identity,
+ };
+
+ dect_ie_init(&portable_identity);
+ portable_identity.type = ID_TYPE_IPUI;
+ portable_identity.ipui = ipuis[PHONE1];
+
+ return dect_mm_access_rights_req(dh, &param);
+}
+
+static struct dect_ops ops = {
+ .mm_ops = &mm_ops,
+};
+
+int main(int argc, char **argv)
+{
+ if (dect_event_ops_init(&ops) < 0)
+ exit(1);
+
+ dh = dect_alloc_handle(&ops);
+ if (dh == NULL)
+ exit(1);
+
+ if (dect_init(dh) < 0)
+ exit(1);
+
+ if (mm_access_rights_request(dh) < 0)
+ exit(1);
+
+ dect_event_loop();
+ dect_close_handle(dh);
+ dect_event_ops_cleanup();
+ return 0;
+}
diff --git a/example/test.c b/example/test.c
new file mode 100644
index 0000000..02c5663
--- /dev/null
+++ b/example/test.c
@@ -0,0 +1,294 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <event.h>
+
+#include <dect/libdect.h>
+#include <dect/terminal.h>
+#include <dect/keypad.h>
+#include "common.h"
+
+struct call {
+ struct dect_keypad_buffer *keybuf;
+ struct dect_audio_handle *audio;
+ struct event event;
+ enum {
+ BLINK0,
+ RING,
+ BLINK1,
+ SCROLLING,
+ } state;
+ uint8_t scroll_off;
+ uint8_t ring_pattern;
+};
+
+enum phones { PHONE1, PHONE2, PHONE3, };
+static const struct dect_ipui ipuis[] = {
+ [PHONE1] = {
+ .put = DECT_IPUI_N,
+ .pun.n.ipei = {
+ .emc = 0x08ae,
+ .psn = 0x83d1e,
+ },
+ },
+ [PHONE2] = {
+ .put = DECT_IPUI_N,
+ .pun.n.ipei = {
+ .emc = 0x08ae,
+ .psn = 0x8969f,
+ },
+ },
+ [PHONE3] = {
+ .put = DECT_IPUI_N,
+ .pun.n.ipei = {
+ .emc = 0x08ae,
+ .psn = 0x5b9a0,
+ },
+ },
+};
+
+static void dect_mncc_timer(int fd, short even, void *data);
+static void dect_mncc_timer_schedule(struct dect_call *call)
+{
+ struct call *priv = dect_call_priv(call);
+ struct timeval tv = { .tv_sec = 1 };
+
+ evtimer_set(&priv->event, dect_mncc_timer, call);
+ evtimer_add(&priv->event, &tv);
+}
+
+static void dect_mncc_timer(int fd, short even, void *data)
+{
+ struct dect_call *call = data;
+ struct dect_ie_display display;
+ struct dect_ie_signal signal;
+ struct dect_mncc_info_param info = {
+ //.signal = &signal,
+ .display = &display,
+ };
+ static int code;
+
+ init_list_head(&info.progress_indicator.list);
+ dect_ie_init(&signal);
+ signal.code = DECT_SIGNAL_ALERTING_BASE | (code % 10);
+
+ dect_display_init(&display);
+ dect_display_append_char(&display, code++);
+
+ dect_mncc_info_req(dh, call, &info);
+ dect_mncc_timer_schedule(call);
+}
+
+static void dect_keypad_complete(struct dect_handle *dh, void *call,
+ struct dect_ie_keypad *keypad)
+{
+ printf("keypad complete: '%.*s'\n", keypad->len, keypad->info);
+}
+
+static void dect_mncc_connect_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_connect_param *param)
+{
+ printf("MNCC_CONNECT-ind\n");
+}
+
+static void dect_mncc_setup_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_setup_param *setup)
+{
+ struct call *priv = dect_call_priv(call);
+ struct dect_ie_signal signal;
+ struct dect_mncc_connect_param connect = {
+ //.signal = &signal,
+ };
+
+ printf("MNCC_SETUP-ind\n");
+ dect_ie_init(&signal);
+ signal.code = DECT_SIGNAL_DIAL_TONE_ON;
+
+ priv->keybuf = dect_keypad_buffer_init(dh, 3, dect_keypad_complete, call);
+ priv->audio = dect_audio_open();
+
+ dect_mncc_connect_req(dh, call, &connect);
+}
+
+static void dect_mncc_setup_ack_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_setup_ack_param *param)
+{
+ printf("MNCC_SETUP_ACK-ind\n");
+}
+
+static void dect_mncc_info_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_info_param *param)
+{
+ struct call *priv = dect_call_priv(call);
+ struct dect_ie_progress_indicator progress_indicator;
+ struct dect_ie_signal signal;
+ struct dect_mncc_info_param info = {
+ .signal = &signal,
+ };
+
+ printf("MNCC_INFO-ind\n");
+ return;
+ dect_keypad_append(dh, priv->keybuf, param->keypad,
+ param->sending_complete);
+
+ dect_ie_init(&signal);
+ signal.code = DECT_SIGNAL_DIAL_TONE_ON;
+
+ dect_ie_init(&progress_indicator);
+ progress_indicator.location = DECT_LOCATION_PRIVATE_NETWORK_SERVING_LOCAL_USER;
+ progress_indicator.progress = DECT_PROGRESS_INBAND_INFORMATION_NOW_AVAILABLE;
+
+ init_list_head(&info.progress_indicator.list);
+ list_add_tail(&progress_indicator.common.list, &info.progress_indicator.list);
+
+ dect_mncc_info_req(dh, call, &info);
+}
+
+static void dect_mncc_send_call_info(struct dect_call *call)
+{
+ struct call *priv = dect_call_priv(call);
+ struct dect_ie_display display;
+ struct dect_ie_signal signal;
+ struct dect_mncc_info_param info = {
+ .display = &display,
+ .signal = &signal,
+ };
+ static const char *text = " kaber ";
+
+ dect_display_init(&display);
+ dect_display_append_char(&display, DECT_C_CLEAR_DISPLAY);
+ dect_display_append_char(&display, '*');
+ dect_display_append(&display, text + priv->scroll_off,
+ strlen(text) - priv->scroll_off);
+ dect_display_append(&display, text, priv->scroll_off);
+ dect_display_append_char(&display, '*');
+
+ dect_ie_init(&signal);
+ if (priv->state == RING) {
+ signal.code = DECT_SIGNAL_ALERTING_BASE | priv->ring_pattern;
+ priv->ring_pattern = (priv->ring_pattern + 1) % 8;
+ } else
+ signal.code = DECT_SIGNAL_ALERTING_BASE | DECT_RING_OFF;
+
+ if (priv->state != SCROLLING)
+ priv->state++;
+ else {
+ priv->scroll_off = (priv->scroll_off + 1) % (strlen(text) + 1);
+ if (priv->scroll_off == 0)
+ priv->state = 0;
+ }
+
+ dect_mncc_info_req(dh, call, &info);
+}
+
+static void dect_mncc_info_timer(int fd, short even, void *data);
+static void dect_mncc_info_timer_schedule(struct dect_call *call)
+{
+ struct call *priv = dect_call_priv(call);
+ struct timeval tv = { .tv_usec = 500000 };
+
+ evtimer_set(&priv->event, dect_mncc_info_timer, call);
+ evtimer_add(&priv->event, &tv);
+}
+
+static void dect_mncc_info_timer(int fd, short even, void *data)
+{
+ struct dect_call *call = data;
+
+ dect_mncc_send_call_info(call);
+ dect_mncc_info_timer_schedule(call);
+}
+
+static void dect_mncc_alert_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_alert_param *param)
+{
+ printf("MNCC_ALERT-ind\n");
+ dect_mncc_info_timer(0, 0, call);
+}
+
+static void dect_mncc_reject_ind(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param)
+{
+ struct call *priv = dect_call_priv(call);
+
+ printf("MNCC_REJECT-ind\n");
+ event_del(&priv->event);
+}
+
+static void dect_open_call(struct dect_handle *dh, const struct dect_ipui *ipui)
+{
+ struct dect_ie_basic_service basic_service;
+ struct dect_mncc_setup_param param = {
+ .basic_service = &basic_service,
+ };
+ struct dect_call *call;
+ struct call *priv;
+
+ call = dect_call_alloc(dh);
+ if (call == NULL)
+ return;
+ priv = dect_call_priv(call);
+
+ dect_ie_init(&basic_service);
+ basic_service.class = DECT_CALL_CLASS_NORMAL;
+ basic_service.service = DECT_SERVICE_BASIC_SPEECH_DEFAULT;
+
+ dect_mncc_setup_req(dh, call, ipui, &param);
+}
+
+static void dect_dl_u_data_ind(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb)
+{
+ struct call *priv = dect_call_priv(call);
+
+ dect_dl_u_data_req(dh, call, mb);
+ dect_audio_queue(priv->audio, mb);
+}
+
+static const struct dect_cc_ops cc_ops = {
+ .priv_size = sizeof(struct call),
+ .mncc_connect_ind = dect_mncc_connect_ind,
+ .mncc_setup_ind = dect_mncc_setup_ind,
+ .mncc_setup_ack_ind = dect_mncc_setup_ack_ind,
+ .mncc_info_ind = dect_mncc_info_ind,
+ .mncc_alert_ind = dect_mncc_alert_ind,
+ .mncc_reject_ind = dect_mncc_reject_ind,
+ .dl_u_data_ind = dect_dl_u_data_ind,
+};
+
+static const struct dect_mm_ops mm_ops = {
+ .mm_access_rights_ind = 0,
+ .mm_access_rights_cfm = 0,
+};
+
+static struct dect_ops ops = {
+ .cc_ops = &cc_ops,
+ .mm_ops = &mm_ops,
+};
+
+int main(int argc, char **argv)
+{
+ if (dect_event_ops_init(&ops) < 0)
+ exit(1);
+
+ dh = dect_alloc_handle(&ops);
+ if (dh == NULL)
+ exit(1);
+
+ if (dect_init(dh) < 0)
+ exit(1);
+
+#if 0
+ //dect_lce_group_ring(dh, 0xf);
+ dect_open_call(dh, &ipuis[PHONE1]);
+ dect_open_call(dh, &ipuis[PHONE3]);
+#else
+ dect_open_call(dh, &ipuis[PHONE2]);
+#endif
+ dect_event_loop();
+ dect_close_handle(dh);
+ dect_event_ops_cleanup();
+ return 0;
+}
diff --git a/include/Makefile.in b/include/Makefile.in
new file mode 100644
index 0000000..dd22db9
--- /dev/null
+++ b/include/Makefile.in
@@ -0,0 +1,3 @@
+install:
+ install -d $(DESTDIR)/usr/include/dect
+ install -m 644 -t $(DESTDIR)/usr/include/dect/ include/dect/*
diff --git a/include/b_fmt.h b/include/b_fmt.h
new file mode 100644
index 0000000..e7acd6d
--- /dev/null
+++ b/include/b_fmt.h
@@ -0,0 +1,48 @@
+#ifndef _DECT_B_FMT_H
+#define _DECT_B_FMT_H
+
+struct dect_short_page_msg {
+ uint8_t hdr;
+ __be16 information;
+} __packed;
+
+/*
+ * LCE request paging messages
+ */
+
+#define DECT_LCE_PAGE_W_FLAG 0x08
+#define DECT_LCE_PAGE_HDR_MASK 0x07
+
+/**
+ * @DECT_LCE_PAGE_U_PLANE_NONE: no U-plane
+ * @DECT_LCE_PAGE_UNKNOWN_RINGING: Unknown MAC service type and Ringing
+ * @DECT_LCE_PAGE_ESCAPE: Escape
+ * @DECT_LCE_PAGE_GENERAL_PURPOSE: General purpose code
+ * @DECT_LCE_PAGE_GENERAL_VOICE: General purpose code for voice service
+ * @DECT_LCE_PAGE_AUXILIARY: Auxiliary code
+ * @DECT_LCE_PAGE_DPRS_INITIAL_SETUP: DPRS initial set-up code
+ * @DECT_LCE_PAGE_DPRS_INITIAL_SETUP: DPRS resume code
+ */
+enum lce_request_page_hdr_codes {
+ DECT_LCE_PAGE_U_PLANE_NONE,
+ DECT_LCE_PAGE_UNKNOWN_RINGING,
+ DECT_LCE_PAGE_ESCAPE,
+ DECT_LCE_PAGE_GENERAL_PURPOSE,
+ DECT_LCE_PAGE_GENERAL_VOICE,
+ DECT_LCE_PAGE_AUXILIARY,
+ DECT_LCE_PAGE_DPRS_INITIAL_SETUP,
+ DECT_LCE_PAGE_DPRS_RESUME,
+};
+
+/* Short format message: group ringing request */
+
+#define DECT_LCE_SHORT_PAGE_RING_PATTERN_MASK 0xf000
+#define DECT_LCE_SHORT_PAGE_RING_PATTERN_SHIFT 12
+
+#define DECT_LCE_SHORT_PAGE_GROUP_MASK 0x0fff
+
+/* Short format message: other cases */
+
+#define DECT_LCE_SHORT_PAGE_TPUI_MASK 0xffff
+
+#endif /* _DECT_B_FMT_H */
diff --git a/include/cc.h b/include/cc.h
new file mode 100644
index 0000000..fe09811
--- /dev/null
+++ b/include/cc.h
@@ -0,0 +1,333 @@
+/*
+ * DECT Call Control
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _DECT_CC_H
+#define _DECT_CC_H
+
+/**
+ * Call Control message types
+ */
+enum dect_cc_msg_types {
+ CC_RESERVED = 0x0,
+ CC_ALERTING = 0x1,
+ CC_CALL_PROC = 0x2,
+ CC_SETUP = 0x5,
+ CC_CONNECT = 0x7,
+ CC_SETUP_ACK = 0xd,
+ CC_CONNECT_ACK = 0xf,
+ CC_SERVICE_CHANGE = 0x20,
+ CC_SERVICE_ACCEPT = 0x21,
+ CC_SERVICE_REJECT = 0x22,
+ CC_RELEASE = 0x4d,
+ CC_RELEASE_COM = 0x5a,
+ CC_IWU_INFO = 0x60,
+ CC_NOTIFY = 0x6e,
+ CC_INFO = 0x7b,
+};
+
+struct dect_cc_setup_msg {
+ struct dect_msg_common common;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_fixed_identity *fixed_identity;
+ struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
+ struct dect_ie_basic_service *basic_service;
+ struct dect_ie_repeat_indicator iwu_attributes;
+ struct dect_ie_repeat_indicator call_attributes;
+ struct dect_ie_repeat_indicator connection_attributes;
+ struct dect_ie_cipher_info *cipher_info;
+ struct dect_ie_connection_identity *connection_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_ext_ho_indicator *ext_ho_indicator;
+ struct dect_ie_terminal_capability *terminal_capability;
+ struct dect_ie_end_to_end_compatibility *end_to_end_compatibility;
+ struct dect_ie_rate_parameters *rate_parameters;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_calling_party_number *calling_party_number;
+ struct dect_ie_called_party_number *called_party_number;
+ struct dect_ie_called_party_subaddress *called_party_subaddress;
+ struct dect_ie_sending_complete *sending_complete;
+ struct dect_ie_repeat_indicator segmented_info;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_calling_party_name *calling_party_name;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_call_information *call_information;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_info_msg {
+ struct dect_msg_common common;
+ struct dect_ie_location_area *location_area;
+ struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_ext_ho_indicator *ext_ho_indicator;
+ struct dect_ie_calling_party_number *calling_party_number;
+ struct dect_ie_called_party_number *called_party_number;
+ struct dect_ie_called_party_subaddress *called_party_subaddress;
+ struct dect_ie_sending_complete *sending_complete;
+ struct dect_ie_test_hook_control *test_hook_control;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_calling_party_name *calling_party_name;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_call_information *call_information;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_setup_ack_msg {
+ struct dect_msg_common common;
+ struct dect_ie_info_type *info_type;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_fixed_identity *fixed_identity;
+ struct dect_ie_location_area *location_area;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_call_attributes *call_attributes;
+ struct dect_ie_connection_attributes *connection_attributes;
+ struct dect_ie_connection_identity *connection_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_ext_ho_indicator *ext_ho_indicator;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_delimiter_request *delimiter_request;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_call_proc_msg {
+ struct dect_msg_common common;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_call_attributes *call_attributes;
+ struct dect_ie_connection_attributes *connection_attributes;
+ struct dect_ie_connection_identity *connection_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_alerting_msg {
+ struct dect_msg_common common;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_call_attributes *call_attributes;
+ struct dect_ie_connection_attributes *connection_attributes;
+ struct dect_ie_connection_identity *connection_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_terminal_capability *terminal_capability;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_connect_msg {
+ struct dect_msg_common common;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_call_attributes *call_attributes;
+ struct dect_ie_connection_attributes *connection_attributes;
+ struct dect_ie_connection_identity *connection_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_ext_ho_indicator *ext_ho_indicator;
+ struct dect_ie_terminal_capability *terminal_capability;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_repeat_indicator segmented_info;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_connect_ack_msg {
+ struct dect_msg_common common;
+ struct dect_ie_display *display;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_release_msg {
+ struct dect_msg_common common;
+ struct dect_ie_release_reason *release_reason;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_repeat_indicator segmented_info;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_release_com_msg {
+ struct dect_msg_common common;
+ struct dect_ie_release_reason *release_reason;
+ struct dect_ie_identity_type *identity_type;
+ struct dect_ie_location_area *location_area;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_connection_attributes *connection_attributes;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_display *display;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_repeat_indicator segmented_info;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_service_change_msg {
+ struct dect_msg_common common;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_service_change_info *service_change_info;
+ struct dect_ie_call_attributes *call_attributes;
+ struct dect_ie_repeat_indicator connection_attributes;
+ struct dect_ie_connection_identity *connection_identity;
+ struct dect_ie_repeat_indicator segmented_info;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_service_accept_msg {
+ struct dect_msg_common common;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_connection_identity *connection_identity;
+ struct dect_ie_repeat_indicator segmented_info;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_service_reject_msg {
+ struct dect_msg_common common;
+ struct dect_ie_release_reason *release_reason;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_connection_attributes *connection_attributes;
+ struct dect_ie_repeat_indicator segmented_info;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_notify_msg {
+ struct dect_msg_common common;
+ struct dect_ie_timer_restart *timer_restart;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_cc_iwu_info_msg {
+ struct dect_msg_common common;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_mms_generic_header *mms_generic_header;
+ struct dect_ie_mms_object_header *mms_object_header;
+ struct dect_ie_repeat_indicator mms_extended_header;
+ struct dect_ie_repeat_indicator time_date;
+ struct dect_ie_repeat_indicator calling_party_number;
+ struct dect_ie_repeat_indicator called_party_number;
+ struct dect_ie_called_party_subaddress *called_party_subaddress;
+ struct dect_ie_segmented_info *segmented_info;
+ struct dect_ie_alphanumeric *alphanumeric;
+ struct dect_ie_repeat_indicator segmented_info2;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_segmented_info *segmented_info3;
+ struct dect_ie_iwu_packet *iwu_packet;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+/**
+ * enum dect_cc_states - CC call states
+ *
+ * @DECT_CC_NULL: T-00/F-00
+ * @DECT_CC_CALL_INITIATED: T-01/F-01
+ * @DECT_CC_OVERLAP_SENDING: T-02/F-02
+ * @DECT_CC_CALL_PROCEEDING: T-03/F-03
+ * @DECT_CC_CALL_DELIVERED: T-04/F-04
+ * @DECT_CC_CALL_PRESENT: T-06/F-06
+ * @DECT_CC_CALL_RECEIVED: T-07/F-07
+ * @DECT_CC_CONNECT_PENDING: T-08
+ * @DECT_CC_ACTIVE: T-10/F-10
+ * @DECT_CC_RELEASE_PENDING: T-19/F-19
+ * @DECT_CC_OVERLAP_RECEIVING: T-22/F-22
+ * @DECT_CC_INCOMING_CALL_PROCEEDING: T-23/F-23
+ */
+enum dect_cc_states {
+ DECT_CC_NULL,
+ DECT_CC_CALL_INITIATED,
+ DECT_CC_OVERLAP_SENDING,
+ DECT_CC_CALL_PROCEEDING,
+ DECT_CC_CALL_DELIVERED,
+ DECT_CC_CALL_PRESENT,
+ DECT_CC_CALL_RECEIVED,
+ DECT_CC_CONNECT_PENDING,
+ DECT_CC_ACTIVE,
+ DECT_CC_RELEASE_PENDING,
+ DECT_CC_OVERLAP_RECEIVING,
+ DECT_CC_INCOMING_CALL_PROCEEDING,
+ __DECT_CC_STATE_MAX
+};
+#define DECT_CC_STATE_MAX (__DECT_CC_STATE_MAX - 1)
+
+/**
+ * @transaction: LCE link transaction
+ * @state: call state
+ * @setup_timer: call setup watchdog timer
+ * @lu_sap: U-Plane file descriptor
+ * @priv: libdect user private storage
+ */
+struct dect_call {
+ struct dect_transaction transaction;
+ struct dect_ie_fixed_identity *ft_id;
+ struct dect_ie_portable_identity *pt_id;
+ enum dect_cc_states state;
+ struct dect_timer *setup_timer;
+ struct dect_fd *lu_sap;
+ uint8_t priv[];
+};
+
+#define DECT_CC_SETUP_TIMEOUT 20 /* seconds */
+
+#endif /* _DECT_CC_H */
diff --git a/include/coms.h b/include/coms.h
new file mode 100644
index 0000000..cc858cb
--- /dev/null
+++ b/include/coms.h
@@ -0,0 +1,15 @@
+#ifndef _LIBDECT_COMS_H
+#define _LIBDECT_COMS_H
+
+/* COMS message types */
+enum dect_coms_msg_types {
+ DECT_COMS_SETUP = 0x5,
+ DECT_COMS_CONNECT = 0x7,
+ DECT_COMS_NOTIFY = 0x8,
+ DECT_COMS_RELEASE = 0x4d,
+ DECT_COMS_RELEASE_COM = 0x5a,
+ DECT_COMS_INFO = 0x7b,
+ DECT_COMS_ACK = 0x78,
+};
+
+#endif /* _LIBDECT_COMS_H */
diff --git a/include/dect/cc.h b/include/dect/cc.h
new file mode 100644
index 0000000..d5c3f65
--- /dev/null
+++ b/include/dect/cc.h
@@ -0,0 +1,246 @@
+/*
+ * DECT Call-Control (CC) NWK <-> IWU interface
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _LIBDECT_DECT_CC_H
+#define _LIBDECT_DECT_CC_H
+
+#include <dect/ie.h>
+
+/**
+ * struct dect_mncc_setup_param - MNCC_SETUP primitive parameters
+ */
+struct dect_mncc_setup_param {
+ struct dect_ie_basic_service *basic_service;
+ struct dect_ie_repeat_indicator iwu_attributes;
+ struct dect_ie_cipher_info *cipher_info;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_terminal_capability *terminal_capability;
+ struct dect_ie_end_to_end_compatibility *end_to_end_compatibility;
+ struct dect_ie_rate_parameters *rate_parameters;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_called_party_number *called_party_number;
+ struct dect_ie_called_party_subaddress *called_party_subaddress;
+ struct dect_ie_calling_party_number *calling_party_number;
+ struct dect_ie_calling_party_name *calling_party_name;
+ struct dect_ie_sending_complete *sending_complete;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_mncc_setup_ack_param {
+ struct dect_ie_info_type *info_type;
+ struct dect_ie_location_area *location_area;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_delimiter_request *delimiter_request;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_mncc_release_param {
+ struct dect_ie_release_reason *release_reason;
+ struct dect_ie_identity_type *identity_type;
+ struct dect_ie_location_area *location_area;
+ struct dect_ie_iwu_attributes *iwu_attributes;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_display *display;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_mncc_call_proc_param {
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_mncc_alert_param {
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_terminal_capability *terminal_capability;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_mncc_connect_param {
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_terminal_capability *terminal_capability;
+ struct dect_ie_transit_delay *transit_delay;
+ struct dect_ie_window_size *window_size;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_mncc_facility_param {
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+};
+
+struct dect_mncc_info_param {
+ struct dect_ie_location_area *location_area;
+ struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_repeat_indicator progress_indicator;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_signal *signal;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_network_parameter *network_parameter;
+ struct dect_ie_called_party_number *called_party_number;
+ struct dect_ie_called_party_subaddress *called_party_subaddress;
+ struct dect_ie_calling_party_number *calling_party_number;
+ struct dect_ie_calling_party_name *calling_party_name;
+ struct dect_ie_sending_complete *sending_complete;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_mncc_modify_param {
+ struct dect_ie_service_change_info *service_change_info;
+ struct dect_ie_repeat_indicator iwu_attributes;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+};
+
+struct dect_mncc_hold_param {
+ struct dect_ie_display *display;
+ struct dect_ie_release_reason *release_reason;
+};
+
+struct dect_mncc_iwu_info_param {
+ struct dect_ie_alphanumeric *alphanumeric;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_iwu_packet *iwu_packet;
+};
+
+struct dect_handle;
+struct dect_call;
+struct dect_msg_buf;
+
+extern struct dect_call *dect_call_alloc(const struct dect_handle *dh);
+extern void *dect_call_priv(struct dect_call *call);
+
+extern const struct dect_ipui *dect_call_portable_identity(const struct dect_call *call);
+
+struct dect_cc_ops {
+ size_t priv_size;
+ void (*mncc_setup_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_setup_param *param);
+ void (*mncc_setup_ack_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_setup_ack_param *param);
+ void (*mncc_reject_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param);
+ void (*mncc_call_proc_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_call_proc_param *param);
+ void (*mncc_alert_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_alert_param *param);
+ void (*mncc_connect_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_connect_param *param);
+ void (*mncc_connect_cfm)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_connect_param *param);
+ void (*mncc_release_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param);
+ void (*mncc_release_cfm)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param);
+ void (*mncc_facility_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_facility_param *param);
+ void (*mncc_info_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_info_param *param);
+ void (*mncc_modify_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_modify_param *param);
+ void (*mncc_modify_cfm)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_modify_param *param);
+ void (*mncc_hold_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+ void (*mncc_hold_cfm)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+ void (*mncc_retrieve_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+ void (*mncc_retrieve_cfm)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+ void (*mncc_iwu_info_ind)(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_iwu_info_param *param);
+
+ void (*dl_u_data_ind)(struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb);
+};
+
+extern 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);
+extern int dect_mncc_setup_ack_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_setup_ack_param *param);
+extern int dect_mncc_reject_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param);
+extern int dect_mncc_call_proc_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_call_proc_param *param);
+extern int dect_mncc_alert_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_alert_param *param);
+extern int dect_mncc_connect_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_connect_param *param);
+extern int dect_mncc_connect_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_connect_param *param);
+extern int dect_mncc_release_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param);
+extern int dect_mncc_release_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_release_param *param);
+extern int dect_mncc_facility_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_facility_param *param);
+extern int dect_mncc_info_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_info_param *param);
+extern int dect_mncc_modify_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_modify_param *param);
+extern int dect_mncc_modify_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_modify_param *param);
+extern int dect_mncc_hold_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+extern int dect_mncc_hold_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+extern int dect_mncc_retrieve_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+extern int dect_mncc_retrieve_res(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_hold_param *param);
+extern int dect_mncc_iwu_info_req(struct dect_handle *dh, struct dect_call *call,
+ const struct dect_mncc_iwu_info_param *param);
+
+extern int dect_dl_u_data_req(const struct dect_handle *dh, struct dect_call *call,
+ struct dect_msg_buf *mb);
+
+#endif /* _LIBDECT_DECT_CC_H */
diff --git a/include/dect/identities.h b/include/dect/identities.h
new file mode 100644
index 0000000..095687a
--- /dev/null
+++ b/include/dect/identities.h
@@ -0,0 +1,169 @@
+/*
+ * DECT Identities
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _LIBDECT_DECT_IDENTITIES_H
+#define _LIBDECT_DECT_IDENTITIES_H
+
+/*
+ * Acess Rights Identity (ARI)
+ */
+
+/**
+ * DECT ARI classes
+ *
+ * @DECT_ARC_A: Residential and private (PBX) single- and small multiple cell systems
+ * @DECT_ARC_B: Private (PABXs) multiple cell
+ * @DECT_ARC_C: Public single and multiple cell systems
+ * @DECT_ARC_D: Public DECT access to a GSM network
+ * @DECT_ARC_E: PP to PP direct communication (private)
+ */
+enum dect_ari_classes {
+ DECT_ARC_A = 0x0,
+ DECT_ARC_B = 0x1,
+ DECT_ARC_C = 0x2,
+ DECT_ARC_D = 0x3,
+ DECT_ARC_E = 0x4,
+};
+
+struct dect_ari {
+ enum dect_ari_classes arc;
+ uint32_t fpn;
+ uint32_t fps;
+ union {
+ uint16_t emc;
+ uint16_t eic;
+ uint16_t poc;
+ uint32_t gop;
+ uint16_t fil;
+ };
+};
+
+enum dect_ari_lengths {
+ DECT_ARC_A_LEN = 36,
+ DECT_ARC_B_LEN = 31,
+ DECT_ARC_C_LEN = 31,
+ DECT_ARC_D_LEN = 31,
+ DECT_ARC_E_LEN = 31,
+};
+
+extern bool dect_ari_cmp(const struct dect_ari *a1, const struct dect_ari *a2);
+extern uint8_t dect_parse_ari(struct dect_ari *ari, uint64_t a);
+extern uint64_t dect_build_ari(const struct dect_ari *ari);
+
+/**
+ * struct dect_park - Portable access rights key
+ *
+ * @park: FP ARI
+ * @pli: FP ARI prefix length
+ */
+struct dect_park {
+ struct dect_ari park;
+ uint8_t pli;
+};
+
+/**
+ * struct dect_ipei - International portable equipment ID
+ *
+ * @emc: Equipment Manufacturer Code
+ * @psn: Portable Equipment Serial Number
+ */
+struct dect_ipei {
+ uint16_t emc;
+ uint32_t psn;
+};
+
+/* IPUI */
+
+#define DECT_IPUI_PUT_MASK 0xf0
+#define DECT_IPUI_PUT_SHIFT 4
+
+/**
+ * @DECT_IPUI_N: Portable user identity type N (residential/default)
+ * @DECT_IPUI_O: Portable user identity type O (private)
+ * @DECT_IPUI_P: Portable user identity type P (public/public access service)
+ * @DECT_IPUI_Q: Portable user identity type Q (public/general)
+ * @DECT_IPUI_R: Portable user identity type R (public/IMSI)
+ * @DECT_IPUI_S: Portable user identity type S (PSTN/ISDN)
+ * @DECT_IPUI_T: Portable user identity type T (private extended)
+ * @DECT_IPUI_U: Portable user identity type U (public/general)
+ */
+enum dect_ipui_types {
+ DECT_IPUI_N = 0x0 << DECT_IPUI_PUT_SHIFT,
+ DECT_IPUI_O = 0x1 << DECT_IPUI_PUT_SHIFT,
+ DECT_IPUI_P = 0x2 << DECT_IPUI_PUT_SHIFT,
+ DECT_IPUI_Q = 0x3 << DECT_IPUI_PUT_SHIFT,
+ DECT_IPUI_R = 0x4 << DECT_IPUI_PUT_SHIFT,
+ DECT_IPUI_S = 0x5 << DECT_IPUI_PUT_SHIFT,
+ DECT_IPUI_T = 0x6 << DECT_IPUI_PUT_SHIFT,
+ DECT_IPUI_U = 0x7 << DECT_IPUI_PUT_SHIFT,
+};
+
+/**
+ * @put: Portable User Identity Type
+ * @pun: Type specific data
+ */
+struct dect_ipui {
+ enum dect_ipui_types put;
+ union {
+ struct {
+ struct dect_ipei ipei;
+ } n;
+ struct {
+ uint64_t number;
+ } o;
+ struct {
+ uint16_t poc;
+ uint8_t acc[10];
+ } p;
+ struct {
+ uint8_t bacn[10];
+ } q;
+ struct {
+ uint64_t imsi;
+ } r;
+ struct {
+ uint64_t number;
+ } s;
+ struct {
+ uint16_t eic;
+ uint64_t number;
+ } t;
+ struct {
+ uint8_t cacn[10];
+ } u;
+ } pun;
+};
+
+extern bool dect_ipui_cmp(const struct dect_ipui *u1,
+ const struct dect_ipui *u2);
+
+/**
+ *
+ */
+enum dect_tpui_types {
+ DECT_TPUI_INDIVIDUAL_ASSIGNED,
+ DECT_TPUI_CONNECTIONLESS_GROUP,
+ DECT_TPUI_CALL_GROUP,
+ DECT_TPUI_INDIVIDUAL_DEFAULT,
+ DECT_TPUI_EMERGENCY,
+};
+
+/**
+ * @type: TPUI type
+ * @tpui: type specific value (20 bits)
+ */
+struct dect_tpui {
+ enum dect_tpui_types type;
+ uint32_t tpui;
+};
+
+extern void dect_default_individual_tpui(struct dect_tpui *tpui,
+ const struct dect_ipui *ipui);
+
+/* Collective broadcast identifier */
+#define DECT_TPUI_CBI 0xcfff
+
+#endif /* _LIBDECT_DECT_IDENTITIES_H */
diff --git a/include/dect/ie.h b/include/dect/ie.h
new file mode 100644
index 0000000..3495502
--- /dev/null
+++ b/include/dect/ie.h
@@ -0,0 +1,767 @@
+/*
+ * DECT S-Format Information Elements
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _LIBDECT_DECT_IE_H
+#define _LIBDECT_DECT_IE_H
+
+#include <string.h>
+#include <dect/utils.h>
+#include <list.h>
+
+/**
+ * struct dect_ie_common - common representation of a DECT IE
+ *
+ * @list: repeat indicator list node
+ * @refcnt: reference count
+ */
+struct dect_ie_common {
+ struct list_head list;
+ unsigned int refcnt;
+};
+
+#define dect_ie_container(res, ie) container_of(ie, typeof(*res), common)
+
+static inline struct dect_ie_common *__dect_ie_init(struct dect_ie_common *ie)
+{
+ ie->refcnt = 1;
+ return ie;
+}
+
+#define dect_ie_init(ie) dect_ie_container(ie, __dect_ie_init(&(ie)->common))
+
+static inline struct dect_ie_common *__dect_ie_hold(struct dect_ie_common *ie)
+{
+ if (ie != NULL)
+ ie->refcnt++;
+ return ie;
+}
+
+#define dect_ie_hold(ie) dect_ie_container(ie, __dect_ie_hold(&(ie)->common))
+
+/* Repeat indicator */
+
+/**
+ * enum dect_ie_list_types - Repeat indicator list types
+ *
+ * @DECT_SFMT_IE_LIST_NORMAL: Non priorized list
+ * @DECT_SFMT_IE_PRIORITIZED: Priorized list
+ */
+enum dect_ie_list_types {
+ DECT_SFMT_IE_LIST_NORMAL = 0x1,
+ DECT_SFMT_IE_LIST_PRIORITIZED = 0x2,
+};
+
+struct dect_ie_repeat_indicator {
+ struct dect_ie_common common;
+ enum dect_ie_list_types type;
+ struct list_head list;
+};
+
+static inline void dect_repeat_indicator_init(struct dect_ie_repeat_indicator *ie)
+{
+ dect_ie_init(ie);
+ init_list_head(&ie->list);
+}
+
+#define dect_foreach_ie(ptr, repeat) \
+ list_for_each_entry(ptr, &(repeat).list, common.list)
+
+static inline void dect_ie_list_move(struct dect_ie_repeat_indicator *to,
+ struct dect_ie_repeat_indicator *from)
+{
+ list_splice_init(&from->list, &to->list);
+}
+
+/* Sending complete */
+
+struct dect_ie_sending_complete {
+ struct dect_ie_common common;
+};
+
+/* Delimiter request */
+
+struct dect_ie_delimiter_request {
+ struct dect_ie_common common;
+};
+
+/* Use TPUI */
+
+struct dect_ie_use_tpui {
+ struct dect_ie_common common;
+};
+
+/* Basic service */
+
+#define DECT_BASIC_SERVICE_CALL_CLASS_MASK 0xf0
+#define DECT_BASIC_SERVICE_CALL_CLASS_SHIFT 4
+
+enum dect_call_classes {
+ DECT_CALL_CLASS_MESSAGE = 0x4,
+ DECT_CALL_CLASS_DECT_ISDN = 0x7,
+ DECT_CALL_CLASS_NORMAL = 0x8,
+ DECT_CALL_CLASS_INTERNAL = 0x9,
+ DECT_CALL_CLASS_EMERGENCY = 0xa,
+ DECT_CALL_CLASS_SERVICE = 0xb,
+ DECT_CALL_CLASS_EXTERNAL_HO = 0xc,
+ DECT_CALL_CLASS_SUPPLEMENTARY_SERVICE = 0xd,
+ DECT_CALL_CLASS_QA_M = 0xe,
+};
+#define DECT_CALL_CLASS_MAX 0xf
+
+#define DECT_BASIC_SERVICE_SERVICE_MASK 0x0f
+
+enum dect_basic_service {
+ DECT_SERVICE_BASIC_SPEECH_DEFAULT = 0x0,
+ DECT_SERVICE_DECT_GSM_IWP = 0x4,
+ DECT_SERVICE_UMTS_IWP = 0x6,
+ DECT_SERVICE_LRMS = 0x5,
+ DECT_SERVICE_GSM_IWP_SMS = 0x6,
+ DECT_SERVICE_WIDEBAND_SPEECH = 0x8,
+ DECT_SERVICE_OTHER = 0xf,
+};
+#define DECT_SERVICE_MAX 0xf
+
+struct dect_ie_basic_service {
+ struct dect_ie_common common;
+ enum dect_call_classes class;
+ enum dect_basic_service service;
+};
+
+/* Release reason */
+
+enum dect_release_reasons {
+ /* general values */
+ DECT_RELEASE_NORMAL = 0x0,
+ DECT_RELEASE_UNEXPECTED_MESSAGE = 0x1,
+ DECT_RELEASE_UNKNOWN_TRANSACTION_IDENTIFIER = 0x2,
+ DECT_RELEASE_MANDATORY_IE_MISSING = 0x3,
+ DECT_RELEASE_INVALID_IE_CONTENTS = 0x4,
+ DECT_RELEASE_INCOMPATIBLE_SERVICE = 0x5,
+ DECT_RELEASE_SERVICE_NOT_IMPLEMENTED = 0x6,
+ DECT_RELEASE_NEGOTIATION_NOT_SUPPORTED = 0x7,
+ DECT_RELEASE_INVALID_IDENTITY = 0x8,
+ DECT_RELEASE_AUTHENTICATION_FAILED = 0x9,
+ DECT_RELEASE_UNKNOWN_IDENTITY = 0xa,
+ DECT_RELEASE_NEGOTIATION_FAILED = 0xb,
+ DECT_RELEASE_TIMER_EXPIRY = 0xd,
+ DECT_RELEASE_PARTIAL_RELEASE = 0xe,
+ DECT_RELEASE_UNKNOWN = 0xf,
+ /* user values */
+ DECT_RELEASE_USER_DETACHED = 0x10,
+ DECT_RELEASE_USER_NOT_IN_RANGE = 0x11,
+ DECT_RELEASE_USER_UNKNOWN = 0x12,
+ DECT_RELEASE_USER_ALREADY_ACTIVE = 0x13,
+ DECT_RELEASE_USER_BUSY = 0x14,
+ DECT_RELEASE_USER_REJECTION = 0x15,
+ DECT_RELEASE_USER_CALL_MODIFY = 0x16,
+ /* external handover values */
+ DECT_RELEASE_EXTERNAL_HANDOVER_NOT_SUPPORTED = 0x21,
+ DECT_RELEASE_NETWORK_PARAMETERS_MISSING = 0x22,
+ DECT_RELEASE_EXTERNAL_HANDOVER_RELEASE = 0x23,
+ /* temporary overload values */
+ DECT_RELEASE_OVERLOAD = 0x31,
+ DECT_RELEASE_INSUFFICIENT_RESOURCES = 0x32,
+ DECT_RELEASE_INSUFFICIENT_BEARERS_AVAILABLE = 0x33,
+ DECT_RELEASE_IWU_CONGESTION = 0x34,
+};
+
+struct dect_ie_release_reason {
+ struct dect_ie_common common;
+ enum dect_release_reasons reason;
+};
+
+/* Display IE (used for both Single Display and Multi Display) */
+
+struct dect_ie_display {
+ struct dect_ie_common common;
+ uint8_t len;
+ uint8_t info[256];
+};
+
+static inline void dect_display_init(struct dect_ie_display *display)
+{
+ dect_ie_init(display);
+ display->len = 0;
+}
+
+static inline void
+dect_display_append_char(struct dect_ie_display *display, char c)
+{
+ display->info[display->len] = c;
+ display->len++;
+}
+
+static inline void dect_display_append(struct dect_ie_display *display,
+ const char *str, size_t len)
+{
+ memcpy(display->info + display->len, str, len);
+ display->len += len;
+}
+
+/* Keypad IE (used for both Single Keypad and Multi Keypad) */
+
+struct dect_ie_keypad {
+ struct dect_ie_common common;
+ uint16_t len;
+ uint8_t info[256];
+};
+
+/* Signal IE */
+
+// FIXME: rename to alerting
+enum dect_ring_patterns {
+ DECT_RING_PATTERN_0 = 0x0,
+ DECT_RING_PATTERN_1 = 0x1,
+ DECT_RING_PATTERN_2 = 0x2,
+ DECT_RING_PATTERN_3 = 0x3,
+ DECT_RING_PATTERN_4 = 0x4,
+ DECT_RING_PATTERN_5 = 0x5,
+ DECT_RING_PATTERN_6 = 0x6,
+ DECT_RING_PATTERN_7 = 0x7,
+ DECT_RING_CONTINUOUS = 0x8,
+ DECT_RING_INCOMING_CALL_RELEASED = 0xa,
+ DECT_RING_INCOMING_CALL_ANSWERED = 0xb,
+ DECT_RING_OFF = 0xf,
+ __DECT_RING_MAX
+};
+#define DECT_RING_MAX (__DECT_RING_MAX - 1)
+
+enum dect_signal_codes {
+ DECT_SIGNAL_DIAL_TONE_ON = 0x0,
+ DECT_SIGNAL_RING_BACK_TONE_ON = 0x1,
+ DECT_SIGNAL_INTERCEPT_TONE_ON = 0x2,
+ DECT_SIGNAL_NETWORK_CONGESTION_TONE_ON = 0x3,
+ DECT_SIGNAL_BUSY_TONE_ON = 0x4,
+ DECT_SIGNAL_CONFIRM_TONE_ON = 0x5,
+ DECT_SIGNAL_ANSWER_TONE_ON = 0x6,
+ DECT_SIGNAL_CALL_WAITING_TONE_ON = 0x7,
+ DECT_SIGNAL_OFF_HOOK_WARNING_TONE_ON = 0x8,
+ DECT_SIGNAL_NEGATIVE_ACKNOWLEDGEMENT_TONE = 0x9,
+ DECT_SIGNAL_TONES_OFF = 0xf,
+ DECT_SIGNAL_ALERTING_BASE = 0x40,
+};
+
+struct dect_ie_signal {
+ struct dect_ie_common common;
+ enum dect_signal_codes code;
+};
+
+static inline struct dect_ie_signal *
+dect_signal_init(struct dect_ie_signal *signal, enum dect_signal_codes code)
+{
+ dect_ie_init(signal);
+ signal->code = code;
+ return signal;
+}
+
+/* Timer restart IE */
+
+enum dect_timer_restart_codes {
+ DECT_TIMER_RESTART = 0x0,
+ DECT_TIMER_STOP = 0x1,
+};
+
+struct dect_ie_timer_restart {
+ struct dect_ie_common common;
+ enum dect_timer_restart_codes code;
+};
+
+/* Test hook control */
+
+enum dect_test_hook_ctrls {
+ DECT_TEST_HOOK_ON_HOOK = 0x0,
+ DECT_TEST_HOOK_OFF_HOOK = 0x1,
+};
+
+struct dect_ie_test_hook_control {
+ struct dect_ie_common common;
+ enum dect_test_hook_ctrls hook;
+};
+
+/* Allocation type IE */
+
+struct dect_ie_allocation_type {
+ struct dect_ie_common common;
+};
+
+/* Alphanumeric IE */
+
+struct dect_ie_alphanumeric {
+ struct dect_ie_common common;
+};
+
+/* Auth type IE */
+
+enum dect_ie_auth_type_identifiers {
+ AUTH_DSAA = 0x1,
+ AUTH_GSM = 0x40,
+ AUTH_UMTS = 0x20,
+ AUTH_PROPRIETARY = 0x7f,
+};
+
+enum dect_ie_auth_key_types {
+ KEY_USER_AUTHENTICATION_KEY = 0x1,
+ KEY_USER_PERSONAL_IDENTITY = 0x3,
+ KEY_AUTHENTICATION_CODE = 0x4,
+};
+
+struct dect_ie_auth_type {
+ struct dect_ie_common common;
+ uint8_t auth_id;
+ uint8_t proprietary_auth_id;
+ uint8_t auth_key_type;
+ uint8_t auth_key_num;
+ uint8_t flags;
+ uint8_t cipher_key_num;
+};
+
+/* Call attributes IE */
+
+struct dect_ie_call_attributes {
+ struct dect_ie_common common;
+};
+
+/* Call identity IE */
+
+struct dect_ie_call_identity {
+ struct dect_ie_common common;
+};
+
+/* Called party number IE */
+
+enum number_type {
+ NUMBER_TYPE_UNKNOWN = 0x0,
+ NUMBER_TYPE_INTERNATIONAL = 0x1,
+ NUMBER_TYPE_NATIONAL = 0x2,
+ NUMBER_TYPE_NETWORK_SPECIFIC = 0x3,
+ NUMBER_TYPE_SUBSCRIBER = 0x4,
+ NUMBER_TYPE_ABBREVIATED = 0x6,
+ NUMBER_TYPE_RESERVED = 0x7,
+};
+
+enum numbering_plan_identification {
+ NPI_UNKNOWN = 0x0,
+ NPI_ISDN_E164 = 0x1,
+ NPI_DATA_PLAN_X121 = 0x3,
+ NPI_TCP_IP = 0x7,
+ NPI_NATIONAL_STANDARD = 0x8,
+ NPI_PRIVATE = 0x9,
+ NPI_SIP = 0xa,
+ NPI_INTERNET_CHARACTER_FORMAT = 0xb,
+ NPI_LAN_MAC_ADDRESS = 0xc,
+ NPI_X400 = 0xd,
+ NPI_PROFILE_SPECIFIC = 0xe,
+ NPI_RESERVED = 0xf,
+};
+
+struct dect_ie_called_party_number {
+ struct dect_ie_common common;
+};
+
+/* Called party subaddress IE */
+
+struct dect_ie_called_party_subaddress {
+ struct dect_ie_common common;
+};
+
+/* Calling party number IE */
+
+struct dect_ie_calling_party_number {
+ struct dect_ie_common common;
+};
+
+/* Cipher info IE */
+
+struct dect_ie_cipher_info {
+ struct dect_ie_common common;
+};
+
+/* Connection attributes IE */
+
+struct dect_ie_connection_attributes {
+ struct dect_ie_common common;
+};
+
+/* Connection identity IE */
+
+struct dect_ie_connection_identity {
+ struct dect_ie_common common;
+};
+
+/* Duration IE */
+
+struct dect_ie_duration {
+ struct dect_ie_common common;
+};
+
+/* End-to-end compatibility IE */
+
+struct dect_ie_end_to_end_compatibility {
+ struct dect_ie_common common;
+};
+
+/* Facility IE */
+
+struct dect_ie_facility {
+ struct dect_ie_common common;
+};
+
+/* Feature activate IE */
+
+struct dect_ie_feature_activate {
+ struct dect_ie_common common;
+};
+
+/* Feature indicate IE */
+
+struct dect_ie_feature_indicate {
+ struct dect_ie_common common;
+};
+
+/* Fixed identity IE */
+
+/**
+ * @ID_TYPE_ARI: Access rights identity
+ * @ID_TYPE_ARI_RPN: Access rights identity plus radio fixed part number
+ * @ID_TYPE_ARI_WRS: Access rights identity plus radio fixed part number for WRS
+ * @ID_TYPE_PARK: Portable access rights key
+ */
+enum fixed_identity_types {
+ ID_TYPE_ARI = 0x00,
+ ID_TYPE_ARI_RPN = 0x01,
+ ID_TYPE_ARI_WRS = 0x02,
+ ID_TYPE_PARK = 0x20,
+};
+
+#define S_VL_IE_FIXED_IDENTITY_MIN_SIZE 2
+
+#define S_VL_IE_FIXED_IDENTITY_TYPE_MASK 0x7f
+#define S_VL_IE_FIXED_IDENTITY_LENGTH_MASK 0x7f
+
+struct dect_ie_fixed_identity {
+ struct dect_ie_common common;
+ enum fixed_identity_types type;
+ struct dect_ari ari;
+ uint8_t rpn;
+};
+
+/* Identity type IE */
+
+struct dect_ie_identity_type {
+ struct dect_ie_common common;
+};
+
+/* Info type IE */
+
+struct dect_ie_info_type {
+ struct dect_ie_common common;
+};
+
+/* InterWorking Unit (IWU) attributes IE */
+
+struct dect_ie_iwu_attributes {
+ struct dect_ie_common common;
+};
+
+/* IWU packet IE */
+
+struct dect_ie_iwu_packet {
+ struct dect_ie_common common;
+};
+
+/* IWU to IWU IE */
+
+struct dect_ie_iwu_to_iwu {
+ struct dect_ie_common common;
+};
+
+/* Key IE */
+
+struct dect_ie_key {
+ struct dect_ie_common common;
+};
+
+/* Location area IE */
+
+struct dect_ie_location_area {
+ struct dect_ie_common common;
+};
+
+/* NetWorK (NWK) assigned identity IE */
+
+struct dect_ie_nwk_assigned_identity {
+ struct dect_ie_common common;
+};
+
+/* Network parameter IE */
+
+struct dect_ie_network_parameter {
+ struct dect_ie_common common;
+};
+
+/* Portable identity IE */
+
+/**
+ * @ID_TYPE_IPUI: International Portable User Identity (IPUI)
+ * @ID_TYPE_IPEI: International Portable Equipment Identity (IPEI)
+ * @ID_TYPE_TPUI: Temporary Portable User Identity (TPUI)
+ */
+enum portable_identity_types {
+ ID_TYPE_IPUI = 0x0,
+ ID_TYPE_IPEI = 0x10,
+ ID_TYPE_TPUI = 0x20,
+};
+
+struct dect_ie_portable_identity {
+ struct dect_ie_common common;
+ enum portable_identity_types type;
+ union {
+ struct dect_ipui ipui;
+ };
+};
+
+/* Progress indicator IE */
+
+enum dect_location {
+ DECT_LOCATION_USER = 0x0,
+ DECT_LOCATION_PRIVATE_NETWORK_SERVING_LOCAL_USER = 0x1,
+ DECT_LOCATION_PUBLIC_NETWORK_SERVING_LOCAL_USER = 0x2,
+ DECT_LOCATION_PRIVATE_NETWORK_SERVING_REMOTE_USER = 0x4,
+ DECT_LOCATION_PUBLIC_NETWORK_SERVING_REMOTE_USER = 0x5,
+ DECT_LOCATION_INTERNATIONAL_NETWORK = 0x7,
+ DECT_LOCATION_NETWORK_BEYONG_INTERWORKING_POINT = 0xa,
+ DECT_LOCATION_NOT_APPLICABLE = 0xf,
+};
+
+enum dect_progress_description {
+ DECT_PROGRESS_NOT_END_TO_END_ISDN = 0x0,
+ DECT_PROGRESS_DESTINATION_ADDRESS_NON_ISDN = 0x2,
+ DECT_PROGRESS_ORIGINATION_ADDRESS_NON_ISDN = 0x3,
+ DECT_PROGRESS_CALL_RETURNED_TO_ISDN = 0x4,
+ DECT_PROGRESS_SERVICE_CHANGE = 0x5,
+ DECT_PROGRESS_INBAND_INFORMATION_NOW_AVAILABLE = 0x8,
+ DECT_PROGRESS_INBAND_INFORMATION_NOT_AVAILABLE = 0x9,
+ DECT_PROGRESS_END_TO_END_ISDN = 0x40,
+};
+
+struct dect_ie_progress_indicator {
+ struct dect_ie_common common;
+ enum dect_location location;
+ enum dect_progress_description progress;
+};
+
+/* RAND IE */
+
+struct dect_ie_rand {
+ struct dect_ie_common common;
+};
+
+/* Rate parameters IE */
+
+struct dect_ie_rate_parameters {
+ struct dect_ie_common common;
+};
+
+/* Reject reason IE */
+
+enum dect_reject_reasons {
+ DECT_REJECT_TPUI_UNKNOWN = 0x1,
+ DECT_REJECT_IPUI_UNKNOWN = 0x2,
+ DECT_REJECT_NETWORK_ASSIGNED_IDENTITY_UNKNOWN = 0x3,
+ DECT_REJECT_IPEI_NOT_ACCEPTED = 0x5,
+ DECT_REJECT_IPUI_NOT_ACCEPTED = 0x6,
+ DECT_REJECT_AUTHENTICATION_FAILED = 0x10,
+ DECT_REJECT_NO_AUTHENTICATION_ALGORITHM = 0x11,
+ DECT_REJECT_AUTHENTICATION_ALGORITHM_NOT_SUPPORTED = 0x12,
+ DECT_REJECT_AUTHENTICATION_KEY_NOT_SUPPORTED = 0x13,
+ DECT_REJECT_UPI_NOT_ENTERED = 0x14,
+ DECT_REJECT_NO_CIPHER_ALGORITHM = 0x17,
+ DECT_REJECT_CIPHER_ALGORITHM_NOT_SUPPORTED = 0x18,
+ DECT_REJECT_CIPHER_KEY_NOT_SUPPORTED = 0x19,
+ DECT_REJECT_INCOMPATIBLE_SERVICE = 0x20,
+ DECT_REJECT_FALSE_LCE_REPLY = 0x21,
+ DECT_REJECT_LATE_LCE_REPLY = 0x22,
+ DECT_REJECT_INVALID_TPUI = 0x23,
+ DECT_REJECT_TPUI_ASSIGNMENT_LIMITS_UNACCEPTABLE = 0x24,
+ DECT_REJECT_INSUFFICIENT_MEMORY = 0x2f,
+ DECT_REJECT_OVERLOAD = 0x30,
+ DECT_REJECT_TEST_CALL_BACK_NORMAL_EN_BLOC = 0x40,
+ DECT_REJECT_TEST_CALL_BACK_NORMAL_PIECEWISE = 0x41,
+ DECT_REJECT_TEST_CALL_BACK_EMERGENCY_EN_BLOC = 0x42,
+ DECT_REJECT_TEST_CALL_BACK_EMERGENCY_PIECEWISE = 0x43,
+ DECT_REJECT_INVALID_MESSAGE = 0x5f,
+ DECT_REJECT_INFORMATION_ELEMENT_ERROR = 0x60,
+ DECT_REJECT_INVALID_INFORMATION_ELEMENT_CONTENTS = 0x64,
+ DECT_REJECT_TIMER_EXPIRY = 0x70,
+ DECT_REJECT_PLMN_NOT_ALLOWED = 0x76,
+ DECT_REJECT_LOCATION_AREA_NOT_ALLOWED = 0x80,
+ DECT_REJECT_LOCATION_NATIONAL_ROAMING_NOT_ALLOWED = 0x81,
+};
+
+struct dect_ie_reject_reason {
+ struct dect_ie_common common;
+ enum dect_reject_reasons reason;
+};
+
+/* RES IE */
+
+struct dect_ie_res {
+ struct dect_ie_common common;
+};
+
+/* RS IE */
+
+struct dect_ie_rs {
+ struct dect_ie_common common;
+};
+
+/* Segmented info IE */
+
+struct dect_ie_segmented_info {
+ struct dect_ie_common common;
+};
+
+/* Service change info IE */
+
+struct dect_ie_service_change_info {
+ struct dect_ie_common common;
+};
+
+/* Service class IE */
+
+struct dect_ie_service_class {
+ struct dect_ie_common common;
+};
+
+/* Setup capability IE */
+
+struct dect_ie_setup_capability {
+ struct dect_ie_common common;
+};
+
+/* Terminal capability IE */
+
+struct dect_ie_terminal_capability {
+ struct dect_ie_common common;
+};
+
+/* Transit delay IE */
+
+struct dect_ie_transit_delay {
+ struct dect_ie_common common;
+};
+
+/* Window size IE */
+
+struct dect_ie_window_size {
+ struct dect_ie_common common;
+};
+
+/* ZAP field IE */
+
+struct dect_ie_zap_field {
+ struct dect_ie_common common;
+};
+
+/* Escape to proprietary IE */
+
+struct dect_ie_escape_to_proprietary {
+ struct dect_ie_common common;
+ uint16_t emc;
+ uint8_t content[];
+};
+
+/* Model identifier IE */
+
+struct dect_ie_model_identifier {
+ struct dect_ie_common common;
+};
+
+/* MMS Generic Header IE */
+
+struct dect_ie_mms_generic_header {
+ struct dect_ie_common common;
+};
+
+/* MMS Object Header IE */
+
+struct dect_ie_mms_object_header {
+ struct dect_ie_common common;
+};
+
+/* MMS Extended Header IE */
+
+struct dect_ie_mms_extended_header {
+ struct dect_ie_common common;
+};
+
+/* Time-Date IE */
+
+struct dect_ie_time_date {
+ struct dect_ie_common common;
+};
+
+/* Ext h/o indicator IE */
+
+struct dect_ie_ext_ho_indicator {
+ struct dect_ie_common common;
+};
+
+/* Authentication Reject Parameter IE */
+
+struct dect_ie_auth_reject_parameter {
+ struct dect_ie_common common;
+};
+
+/* Calling party Name IE */
+
+struct dect_ie_calling_party_name {
+ struct dect_ie_common common;
+};
+
+/* Codec List IE */
+
+struct dect_ie_codec_list {
+ struct dect_ie_common common;
+};
+
+/* Events notification IE */
+
+enum dect_event_types {
+ DECT_EVENT_MESSAGE_WAITING = 0x0,
+ DECT_EVENT_MISSED_CALL = 0x1,
+ DECT_EVENT_WEB_CONTENT = 0x2,
+ DECT_EVENT_LIST_CHANGE_INDICATION = 0x3,
+};
+
+enum dect_event_message_waiting_subtypes {
+ DECT_EVENT_MESSAGE_WAITING_UNKNOWN = 0x0,
+ DECT_EVENT_MESSAGE_WAITING_VOICE = 0x1,
+ DECT_EVENT_MESSAGE_WAITING_SMS = 0x2,
+ DECT_EVENT_MESSAGE_WAITING_EMAIL = 0x3,
+};
+
+enum dect_event_missed_call_subtypes {
+ DECT_EVENT_MISSED_CALL_UNKNOWN = 0x0,
+ DECT_EVENT_MISSED_CALL_VOICE = 0x1,
+};
+
+enum dect_event_web_content_subtypes {
+ DECT_EVENT_WEB_CONTENT_UNKNOWN = 0x0,
+ DECT_EVENT_WEB_CONTENT_RSS = 0x1,
+};
+
+struct dect_ie_events_notification {
+ struct dect_ie_common common;
+};
+
+/* Call information IE */
+
+struct dect_ie_call_information {
+ struct dect_ie_common common;
+};
+
+#endif /* _LIBDECT_DECT_IE_H */
diff --git a/include/dect/keypad.h b/include/dect/keypad.h
new file mode 100644
index 0000000..0a38f0a
--- /dev/null
+++ b/include/dect/keypad.h
@@ -0,0 +1,15 @@
+#ifndef _LIBDECT_DECT_KEYPAD
+#define _LIBDECT_DECT_KEYPAD
+
+extern struct dect_keypad_buffer *
+dect_keypad_buffer_init(const struct dect_handle *dh, uint8_t timeout,
+ void (*complete)(struct dect_handle *, void *data,
+ struct dect_ie_keypad *keypad),
+ void *priv);
+
+extern void dect_keypad_append(struct dect_handle *dh,
+ struct dect_keypad_buffer *buf,
+ const struct dect_ie_keypad *keypad,
+ bool sending_complete);
+
+#endif /* _LIBDECT_DECT_KEYPAD */
diff --git a/include/dect/libdect.h b/include/dect/libdect.h
new file mode 100644
index 0000000..3b79e99
--- /dev/null
+++ b/include/dect/libdect.h
@@ -0,0 +1,134 @@
+/*
+ * libdect main header file
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _LIBDECT_DECT_LIBDECT_H
+#define _LIBDECT_DECT_LIBDECT_H
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <dect/identities.h>
+#include <dect/cc.h>
+#include <dect/mm.h>
+
+struct dect_handle;
+
+/**
+ * struct dect_msg_buf - DECT message buffer
+ *
+ * @list: Data link TX queue node
+ * @type: Message type
+ * @len: Data length
+ * @data: Data pointer
+ * @head: Storage area for on-stack buffers
+ */
+struct dect_msg_buf {
+ struct list_head list;
+ uint8_t type;
+ uint8_t len;
+ uint8_t *data;
+ uint8_t head[128];
+};
+
+extern struct dect_msg_buf *dect_mbuf_alloc(const struct dect_handle *dh);
+
+static inline void dect_mbuf_pull(struct dect_msg_buf *mb, unsigned int len)
+{
+ assert(len <= mb->len);
+ mb->data += len;
+ mb->len -= len;
+}
+
+static inline void dect_mbuf_push(struct dect_msg_buf *mb, unsigned int len)
+{
+ mb->data -= len;
+ mb->len += len;
+ assert(mb->data >= mb->head);
+}
+
+static inline void dect_mbuf_reserve(struct dect_msg_buf *mb, unsigned int len)
+{
+ mb->data += len;
+ assert(mb->data < mb->head + sizeof(mb->head));
+}
+
+/**
+ * enum dect_fd_events - file descriptor events
+ *
+ * @DECT_FD_READ: fd readable
+ * @DECT_FD_WRITE: fd writable
+ */
+enum dect_fd_events {
+ DECT_FD_READ = 0x1,
+ DECT_FD_WRITE = 0x2
+};
+
+/**
+ * struct dect_fd - libdect file descriptor
+ *
+ * @callback: callback to invoke for events
+ * @fd: file descriptor numer
+ * @data: libdect internal data
+ * @priv: libdect user private file-descriptor storage
+ */
+struct dect_fd {
+ void (*callback)(struct dect_handle *,
+ struct dect_fd *, uint32_t);
+ int fd;
+ void *data;
+ uint8_t priv[];
+};
+
+/**
+ * struct dect_timer - libdect timer
+ *
+ * @callback: callback to invoke on timer expiry
+ * @data: libdect internal data
+ * @priv: libdect user private timer storage
+ */
+struct dect_timer {
+ void (*callback)(struct dect_handle *,
+ struct dect_timer *);
+ void *data;
+ uint8_t priv[];
+};
+
+struct timeval;
+struct dect_event_ops {
+ size_t fd_priv_size;
+ size_t timer_priv_size;
+
+ int (*register_fd)(const struct dect_handle *dh,
+ struct dect_fd *dfd,
+ uint32_t events);
+ void (*unregister_fd)(const struct dect_handle *dh,
+ struct dect_fd *dfd);
+
+ void (*start_timer)(const struct dect_handle *dh,
+ struct dect_timer *timer,
+ const struct timeval *tv);
+ void (*stop_timer)(const struct dect_handle *dh,
+ struct dect_timer *timer);
+};
+
+struct dect_ops {
+ void *(*malloc)(size_t size);
+ void (*free)(void *ptr);
+
+ const struct dect_event_ops *event_ops;
+ const struct dect_cc_ops *cc_ops;
+ const struct dect_mm_ops *mm_ops;
+};
+
+extern struct dect_handle *dect_alloc_handle(struct dect_ops *ops);
+extern void dect_close_handle(struct dect_handle *dh);
+
+extern int dect_init(struct dect_handle *dh);
+
+extern void dect_set_debug_hook(void (*fn)(const char *fmt, va_list ap));
+
+#endif /* _LIBDECT_DECT_LIBDECT_H */
diff --git a/include/dect/mm.h b/include/dect/mm.h
new file mode 100644
index 0000000..34c5757
--- /dev/null
+++ b/include/dect/mm.h
@@ -0,0 +1,38 @@
+/*
+ * DECT Mobility Management (MM) NWK <-> IWU interface
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _LIBDECT_DECT_MM_H
+#define _LIBDECT_DECT_MM_H
+
+#include <dect/ie.h>
+
+struct dect_mm_access_rights_param {
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_fixed_identity *fixed_identity;
+ struct dect_ie_location_area *location_area;
+ struct dect_ie_auth_type *auth_type;
+ struct dect_ie_cipher_info *cipher_info;
+ struct dect_ie_zap_field *zap_field;
+ struct dect_ie_service_class *service_class;
+ struct dect_ie_model_identifier *model_identifier;
+ struct dect_ie_reject_reason *reject_reason;
+ struct dect_ie_duration *duration;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+};
+
+struct dect_mm_ops {
+ void (*mm_access_rights_ind)(struct dect_handle *dh,
+ const struct dect_mm_access_rights_param *param);
+ void (*mm_access_rights_cfm)(struct dect_handle *dh,
+ const struct dect_mm_access_rights_param *param);
+};
+
+extern int dect_mm_access_rights_req(struct dect_handle *dh,
+ const struct dect_mm_access_rights_param *param);
+extern int dect_mm_access_rights_res(struct dect_handle *dh,
+ const struct dect_mm_access_rights_param *param);
+
+#endif /* _LIBDECT_DECT_MM_H */
diff --git a/include/dect/terminal.h b/include/dect/terminal.h
new file mode 100644
index 0000000..b7fdf0e
--- /dev/null
+++ b/include/dect/terminal.h
@@ -0,0 +1,70 @@
+#ifndef _LIBDECT_DECT_TERMINAL
+#define _LIBDECT_DECT_TERMINAL
+
+/*
+ * DECT Standard 8-bit characters
+ *
+ * DECT Control codes from 0x00 - 0x1f. Characters between 0x20 and 0x7f
+ * are IA5 coded.
+ */
+
+/**
+ * @DECT_C_CANCEL_DTMF: Null/Cancel DTMF tone
+ * @DECT_C_RETURN_HOME: Return home
+ * @DECT_C_RETURN_END: Return end
+ * @DECT_C_DIALING_PAUSE: Dialing Pause
+ * @DECT_C_MOVE_NEXT_TAB: Move forward to next column tab position
+ * @DECT_C_MOVE_PREV_TAB: Move backward to next column tab position
+ * @DECT_C_MOVE_PREV_COL: Move backward one column
+ * @DECT_C_MOVE_NEXT_COL: Move forward one column
+ * @DECT_C_MOVE_NEXT_ROW: Move down one row
+ * @DECT_C_MOVE_PREV_ROW: Move up one row
+ * @DECT_C_CLEAR_DISPLAY: Clear display (and return home)
+ * @DECT_C_RETURN: Return (to start of current row)
+ * @DECT_C_FLASH_OFF: Flash off
+ * @DECT_C_FLASH_ON: Flash on
+ * @DECT_C_XON: XON (resume transmission)
+ * @DECT_C_PULSE_DIALING: Go to pulse dialing
+ * @DECT_C_XOFF: XOFF (stop transmission)
+ * @DECT_C_DTMF_DIALING_DEFINED: Go to DTMF dialing mode; defined tone length
+ * @DECT_C_REGISTER_RECALL: Register recall
+ * @DECT_C_DTMF_DIALING_INFINITE: Go to DTMF dialing mode; infinite tone length
+ * @DECT_C_INTERNAL_CALL: Internal call
+ * @DECT_C_SERVICE: Service
+ * @DECT_C_CLEAR_TO_END_OF_DISPLAY: Clear to end of display (maintain cursor position)
+ * @DECT_C_CLEAR_TO_END_OF_LINE: Clear to end of line (maintain cursor position)
+ * @DECT_C_ESC: ESCape in the IA5 sense
+ *
+ * Flash on/off is a toggle action that applies to all following characters.
+ */
+enum dect_control_characters {
+ DECT_C_CANCEL_DTMF = 0x0,
+ DECT_C_RETURN_HOME = 0x2,
+ DECT_C_RETURN_END = 0x3,
+ DECT_C_DIALING_PAUSE = 0x5,
+ DECT_C_MOVE_NEXT_TAB = 0x6,
+ DECT_C_MOVE_PREV_TAB = 0x7,
+ DECT_C_MOVE_PREV_COL = 0x8,
+ DECT_C_MOVE_NEXT_COL = 0x9,
+ DECT_C_MOVE_NEXT_ROW = 0xa,
+ DECT_C_MOVE_PREV_ROW = 0xb,
+ DECT_C_CLEAR_DISPLAY = 0xc,
+ DECT_C_RETURN = 0xd,
+ DECT_C_FLASH_OFF = 0xe,
+ DECT_C_FLASH_ON = 0xf,
+ DECT_C_XON = 0x11,
+ DECT_C_PULSE_DIALING = 0x12,
+ DECT_C_XOFF = 0x13,
+ DECT_C_DTMF_DIALING_DEFINED = 0x14,
+ DECT_C_REGISTER_RECALL = 0x15,
+ DECT_C_DTMF_DIALING_INFINITE = 0x16,
+ DECT_C_INTERNAL_CALL = 0x17,
+ DECT_C_SERVICE = 0x18,
+ DECT_C_CLEAR_TO_END_OF_DISPLAY = 0x19,
+ DECT_C_CLEAR_TO_END_OF_LINE = 0x1a,
+ DECT_C_ESC = 0x1b
+};
+
+#define DECT_TABSIZE 10
+
+#endif /* _LIBDECT_DECT_TERMINAL */
diff --git a/include/dect/utils.h b/include/dect/utils.h
new file mode 100644
index 0000000..06ea591
--- /dev/null
+++ b/include/dect/utils.h
@@ -0,0 +1,8 @@
+#ifndef _LIBDECT_DECT_UTILS_H
+#define _LIBDECT_DECT_UTILS_H
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#endif /* _LIBDECT_DECT_UTILS_H */
diff --git a/include/identities.h b/include/identities.h
new file mode 100644
index 0000000..c536376
--- /dev/null
+++ b/include/identities.h
@@ -0,0 +1,121 @@
+#ifndef _DECT_IDENTITIES_H
+#define _DECT_IDENTITIES_H
+
+/*
+ * Acess Rights Identity (ARI)
+ */
+
+#define DECT_ARI_ARC_MASK 0xe000000000000000ULL
+#define DECT_ARI_ARC_SHIFT 61
+
+/* Class A */
+#define DECT_ARI_A_EMC_MASK 0x1fffe00000000000ULL
+#define DECT_ARI_A_EMC_SHIFT 45
+
+#define DECT_ARI_A_FPN_MASK 0x00001ffff0000000ULL
+#define DECT_ARI_A_FPN_SHIFT 28
+
+/* Class B */
+#define DECT_ARI_B_EIC_MASK 0x1fffe00000000000ULL
+#define DECT_ARI_B_EIC_SHIFT 45
+
+#define DECT_ARI_B_FPN_MASK 0x00001fe000000000ULL
+#define DECT_ARI_B_FPN_SHIFT 37
+
+#define DECT_ARI_B_FPS_MASK 0x0000001e00000000ULL
+#define DECT_ARI_B_FPS_SHIFT 33
+
+/* Class C */
+#define DECT_ARI_C_POC_MASK 0x1fffe00000000000ULL
+#define DECT_ARI_C_POC_SHIFT 45
+
+#define DECT_ARI_C_FPN_MASK 0x00001fe000000000ULL
+#define DECT_ARI_C_FPN_SHIFT 37
+
+#define DECT_ARI_C_FPS_MASK 0x0000001e00000000ULL
+#define DECT_ARI_C_FPS_SHIFT 33
+
+/* Class D */
+#define DECT_ARI_D_GOP_MASK 0x1ffffe0000000000ULL
+#define DECT_ARI_D_GOP_SHIFT 41
+
+#define DECT_ARI_D_FPN_MASK 0x000001fe00000000ULL
+#define DECT_ARI_D_FPN_SHIFT 33
+
+/* Class E */
+#define DECT_ARI_E_FIL_MASK 0x1fffe00000000000ULL
+#define DECT_ARI_E_FIL_SHIFT 45
+
+#define DECT_ARI_E_FPN_MASK 0x00001ffe00000000ULL
+#define DECT_ARI_E_FPN_SHIFT 33
+
+
+/*
+ * IPEI
+ */
+
+#define DECT_IPEI_EMC_MASK 0x0000000ffff00000ULL
+#define DECT_IPEI_EMC_SHIFT 20
+
+#define DECT_IPEI_PSN_MASK 0x00000000000fffffULL
+
+/*
+ * IPUI
+ */
+
+#define DECT_IPUI_PUT_MASK 0xf0
+
+extern bool dect_parse_ipui(struct dect_ipui *ipui,
+ const uint8_t *ptr, uint8_t len);
+extern uint8_t dect_build_ipui(uint8_t *ptr, const struct dect_ipui *ipui);
+
+/*
+ * TPUI
+ */
+
+#define DECT_TPUI_CONNECTIONLESS_GROUP_ID 0xcc000
+
+#define DECT_TPUI_CALL_GROUP_ID 0xdd000
+
+#define DECT_TPUI_DEFAULT_INDIVIDUAL_ID 0xe0000
+#define DECT_TPUI_DEFAULT_INDIVIDUAL_IPUI_MASK 0x0ffff
+
+#define DECT_TPUI_EMERGENCY_ID 0xf1000
+
+/*
+ * PMID (Portable Part Identifier)
+ */
+
+#define DECT_PMID_MASK 0x000fffff
+#define DECT_PMID_SIZE 20
+
+#define DECT_PMID_DEFAULT_ID_MASK 0x000f0000
+#define DECT_PMID_DEFAULT_ID 0x000e0000
+#define DECT_PMID_DEFAULT_NUM_MASK 0x0000ffff
+
+#define DECT_PMID_EMERGENCY_ID_MASK 0x000ff000
+#define DECT_PMID_EMERGENCY_ID 0x000f1000
+#define DECT_PMID_EMERGENCY_TPUI_MASK 0x00000fff
+
+#define DECT_PMID_ASSIGNED_TPUI_MASK 0x000fffff
+
+/**
+ * @DECT_PMID_DEFAULT: 1110 + arbitrary number (16 bits)
+ * @DECT_PMID_ASSIGNED: Assigned individual TPUI
+ * @DECT_PMID_EMERGENCY: 1111 0001 + 12 bits of emergency TPUI
+ */
+enum dect_pmid_types {
+ DECT_PMID_DEFAULT,
+ DECT_PMID_ASSIGNED,
+ DECT_PMID_EMERGENCY,
+};
+
+struct dect_pmid {
+ enum dect_pmid_types type;
+ union {
+ uint32_t tpui;
+ uint32_t num;
+ };
+};
+
+#endif /* _DECT_IDENTITIES_H */
diff --git a/include/lce.h b/include/lce.h
new file mode 100644
index 0000000..15b4ee6
--- /dev/null
+++ b/include/lce.h
@@ -0,0 +1,197 @@
+/*
+ * DECT Link Control Entity (LCE)
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _DECT_LCE_H
+#define _DECT_LCE_H
+
+#include <assert.h>
+#include <linux/dect.h>
+#include <list.h>
+#include <s_fmt.h>
+#include <utils.h>
+
+static inline void dect_mbuf_dump(const struct dect_msg_buf *mb,
+ const char *prefix)
+{
+ dect_hexdump(prefix, mb->data, mb->len);
+}
+
+/**
+ * enum dect_transaction_role - the LCE's role in a transaction
+ *
+ * @DECT_TRANSACTION_INITIATOR: Transaction was initiated by higher layer protocol entity
+ * @DECT_TRANSACTION_RESPONDER: Transaction was initiated by network
+ */
+enum dect_transaction_role {
+ DECT_TRANSACTION_INITIATOR,
+ DECT_TRANSACTION_RESPONDER,
+};
+
+/* Connectionless NWK layer transaction value */
+#define DECT_TV_CONNECTIONLESS 6
+
+/**
+ * struct dect_transaction - DECT protocol transaction
+ *
+ * @list: Datalink transaction list node
+ * @link: Associated data link
+ * @pd: Protocol discriminator
+ * @role: Role (initiator/responder)
+ * @tv: Transaction value
+ */
+enum dect_s_pd_values;
+struct dect_transaction {
+ struct list_head list;
+ struct dect_data_link *link;
+ enum dect_s_pd_values pd;
+ enum dect_transaction_role role;
+ uint16_t tv;
+};
+
+extern int dect_open_transaction(struct dect_handle *dh,
+ struct dect_transaction *ta,
+ const struct dect_ipui *ipui);
+extern void dect_confirm_transaction(struct dect_handle *dh,
+ struct dect_transaction *ta,
+ const struct dect_transaction *req);
+extern void dect_close_transaction(struct dect_handle *dh,
+ struct dect_transaction *ta);
+extern void dect_transaction_get_ulei(struct sockaddr_dect_lu *addr,
+ const struct dect_transaction *ta);
+
+extern 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_nwk_protocol - NWK layer protocol
+ *
+ * @name: Protocol name
+ * @pd: Protocol discriminator
+ * @open: Open a new transaction initiated by the network
+ * @shutdown: Perform an active shutdown of the transaction
+ * @rcv: Receive a message related to an active transaction
+ */
+struct dect_nwk_protocol {
+ const char *name;
+ enum dect_s_pd_values pd;
+ uint16_t max_transactions;
+ void (*open)(struct dect_handle *dh,
+ const struct dect_transaction *req,
+ struct dect_msg_buf *mb);
+ void (*shutdown)(struct dect_handle *dh,
+ struct dect_transaction *req);
+ void (*rcv)(struct dect_handle *dh,
+ struct dect_transaction *ta,
+ struct dect_msg_buf *mb);
+};
+
+extern void dect_lce_register_protocol(const struct dect_nwk_protocol *protocol);
+
+/**
+ * struct dect_lte - Location Table Entry
+ *
+ * @list: Location table list node
+ * @ipui: International Portable User ID
+ * @tpui: Temporary Portable User ID
+ */
+struct dect_lte {
+ struct list_head list;
+ struct dect_ipui ipui;
+ struct dect_tpui tpui;
+};
+
+struct dect_location_table {
+ struct list_head entries;
+};
+
+enum dect_data_link_states {
+ DECT_DATA_LINK_RELEASED,
+ DECT_DATA_LINK_ESTABLISHED,
+ DECT_DATA_LINK_ESTABLISH_PENDING,
+ DECT_DATA_LINK_RELEASE_PENDING,
+ DECT_DATA_LINK_SUSPENDED,
+ DECT_DATA_LINK_SUSPEND_PENDING,
+ DECT_DATA_LINK_RESUME_PENDING,
+ __DECT_DATA_LINK_STATE_MAX
+};
+#define DECT_DATA_LINK_STATE_MAX (__DECT_DATA_LINK_STATE_MAX - 1)
+
+/**
+ * struct dect_data_link
+ *
+ * @list: DECT handle link list node
+ * @dfd: Associated socket file descriptor
+ * @dlei: Data Link Endpoint identifier
+ * @ipui: International Portable User ID
+ * @state: Data link state
+ * @sdu_timer: Establish without SDU timer
+ * @msg_queue: Message queue used during ESTABLISH_PENDING state
+ */
+struct dect_data_link {
+ struct list_head list;
+ struct sockaddr_dect_ssap dlei;
+ struct dect_ipui ipui;
+ struct dect_fd *dfd;
+ enum dect_data_link_states state;
+ struct dect_timer *sdu_timer;
+ struct list_head transactions;
+ struct list_head msg_queue;
+};
+
+#define DECT_DDL_ESTABLISH_SDU_TIMEOUT 5 /* seconds */
+
+extern int dect_lce_group_ring(struct dect_handle *dh,
+ enum dect_ring_patterns pattern);
+
+/* LCE message types */
+enum dect_lce_msg_types {
+ DECT_LCE_PAGE_RESPONSE = 0x71,
+ DECT_LCE_PAGE_REJECT = 0x72,
+};
+
+/**
+ * struct dect_lce_page_response - LCE Page response S-Format message
+ *
+ * @common: Message header
+ * @portable_identity: Portable Identity IE
+ * @fixed_identity: Fixed Identity IE
+ * @nwk_assigned_identity: NWK-assigned Identity IE (optional)
+ * @cipher_info: Cipher Info IE (optional)
+ * @escape_to_proprietary: Escape to proprietary IE (optional)
+ */
+struct dect_lce_page_response {
+ struct dect_msg_common common;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_fixed_identity *fixed_identity;
+ struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
+ struct dect_ie_cipher_info *cipher_info;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+/**
+ * struct dect_lce_page_reject - LCE Page reject S-Format message
+ *
+ * @common: Message header
+ * @portable_identity: Portable Identity IE
+ * @fixed_identity: Fixed Identity IE
+ * @reject_reason: Reject reason IE
+ * @escape_to_proprietary: Escape to proprietary IE (optional)
+ */
+struct dect_lce_page_reject {
+ struct dect_msg_common common;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_fixed_identity *fixed_identity;
+ struct dect_ie_reject_reason *reject_reason;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+extern int dect_lce_init(struct dect_handle *dh);
+extern void dect_lce_exit(struct dect_handle *dh);
+
+#endif /* _DECT_LCE_H */
diff --git a/include/libdect.h b/include/libdect.h
new file mode 100644
index 0000000..d400fea
--- /dev/null
+++ b/include/libdect.h
@@ -0,0 +1,35 @@
+#ifndef _LIBDECT_H
+#define _LIBDECT_H
+
+#include <linux/dect_netlink.h>
+#include <dect/libdect.h>
+#include <list.h>
+
+/**
+ * struct dect_handle - libdect handle
+ *
+ * @ops: user ops
+ * @nlsock: netlink socket
+ * @nlfd: netlink file descriptor
+ * @index: cluster index
+ * @mode: cluster mode
+ * @pari: FP's PARI
+ * @b_sap: B-SAP socket
+ * @s_sap: S-SAP listener socket
+ * @links: list of data links
+ */
+struct dect_handle {
+ const struct dect_ops *ops;
+ struct nl_sock *nlsock;
+ struct dect_fd *nlfd;
+
+ unsigned int index;
+ enum dect_cluster_modes mode;
+ struct dect_ari pari;
+
+ struct dect_fd *b_sap;
+ struct dect_fd *s_sap;
+ struct list_head links;
+};
+
+#endif /* _LIBDECT_H */
diff --git a/include/linux/dect.h b/include/linux/dect.h
new file mode 100644
index 0000000..2135800
--- /dev/null
+++ b/include/linux/dect.h
@@ -0,0 +1,76 @@
+#ifndef _LINUX_DECT_H
+#define _LINUX_DECT_H
+
+#define DECTNAMSIZ 16
+
+#include <linux/types.h>
+#include <linux/socket.h>
+
+/* these have to be macros in order to be usable for module aliases */
+#define DECT_RAW 0 /* raw frames */
+#define DECT_B_SAP 1 /* DLC Broadcast Service */
+#define DECT_S_SAP 2 /* DLC Data Link Service */
+#define DECT_LU1_SAP 3 /* LU1 sockets */
+#define DECT_PROTO_NUM 4
+
+/**
+ * struct sockaddr_dect
+ *
+ * @dect_family: address family (AF_DECT)
+ * @dect_index: cluster index
+ */
+struct sockaddr_dect {
+ sa_family_t dect_family;
+ int dect_index;
+};
+
+/* raw sockets */
+
+#define DECT_RAW_AUXDATA 0
+
+/**
+ * struct dect_raw_auxdata - raw socket auxiliary frame data
+ *
+ * @mfn: multi-frame number
+ * @frame: frame number
+ * @slot: slot numer
+ * @rssi: receive signal strength indicator
+ */
+struct dect_raw_auxdata {
+ __u32 mfn;
+ __u8 frame;
+ __u8 slot;
+ __u8 rssi;
+};
+
+/**
+ * struct sockaddr_dect_ssap
+ *
+ * @dect_family: family (AF_DECT)
+ * @dect_dlei: Data Link Endpoint Identifier
+ * @dect_class: Class A/B
+ */
+struct sockaddr_dect_ssap {
+ sa_family_t dect_family;
+ __u64 dect_ari:40,
+ dect_pmid:20,
+ dect_lcn:3;
+ __u8 dect_lln:4,
+ dect_sapi:4;
+ __u8 dect_class;
+};
+
+/**
+ * struct sockaddr_dect_lu - DLC U-plane LUx service instance address
+ *
+ * @dect_family: address family (AF_DECT)
+ * @dect_mci: MAC Connection Identifier
+ */
+struct sockaddr_dect_lu {
+ sa_family_t dect_family;
+ __u64 dect_ari:40,
+ dect_pmid:20,
+ dect_lcn:3;
+};
+
+#endif /* _LINUX_DECT_H */
diff --git a/include/linux/socket.h b/include/linux/socket.h
new file mode 100644
index 0000000..cec9b65
--- /dev/null
+++ b/include/linux/socket.h
@@ -0,0 +1,306 @@
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define _K_SS_MAXSIZE 128 /* Implementation specific max size */
+#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *))
+ /* Implementation specific desired alignment */
+
+struct __kernel_sockaddr_storage {
+ unsigned short ss_family; /* address family */
+ /* Following field(s) are implementation specific */
+ char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
+ /* space to achieve desired size, */
+ /* _SS_MAXSIZE value minus size of ss_family */
+} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#include <asm/socket.h> /* arch-dependent defines */
+#include <linux/sockios.h> /* the SIOCxxx I/O controls */
+#include <linux/uio.h> /* iovec support */
+#include <linux/types.h> /* pid_t */
+ /* */
+
+
+typedef unsigned short sa_family_t;
+
+/*
+ * 1003.1g requires sa_family_t and that sa_data is char.
+ */
+
+struct sockaddr {
+ sa_family_t sa_family; /* address family, AF_xxx */
+ char sa_data[14]; /* 14 bytes of protocol address */
+};
+
+struct linger {
+ int l_onoff; /* Linger active */
+ int l_linger; /* How long to linger for */
+};
+
+#define sockaddr_storage __kernel_sockaddr_storage
+
+/*
+ * As we do 4.4BSD message passing we use a 4.4BSD message passing
+ * system, not 4.3. Thus msg_accrights(len) are now missing. They
+ * belong in an obscure libc emulation or the bin.
+ */
+
+struct msghdr {
+ void * msg_name; /* Socket name */
+ int msg_namelen; /* Length of name */
+ struct iovec * msg_iov; /* Data blocks */
+ __kernel_size_t msg_iovlen; /* Number of blocks */
+ void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
+ __kernel_size_t msg_controllen; /* Length of cmsg list */
+ unsigned msg_flags;
+};
+
+/*
+ * POSIX 1003.1g - ancillary data object information
+ * Ancillary data consits of a sequence of pairs of
+ * (cmsghdr, cmsg_data[])
+ */
+
+struct cmsghdr {
+ __kernel_size_t cmsg_len; /* data byte count, including hdr */
+ int cmsg_level; /* originating protocol */
+ int cmsg_type; /* protocol-specific type */
+};
+
+/*
+ * Ancilliary data object information MACROS
+ * Table 5-14 of POSIX 1003.1g
+ */
+
+#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg))
+#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
+
+#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
+
+#define CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
+#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+
+#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \
+ (struct cmsghdr *)(ctl) : \
+ (struct cmsghdr *)NULL)
+#define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
+ (cmsg)->cmsg_len <= (unsigned long) \
+ ((mhdr)->msg_controllen - \
+ ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
+
+/*
+ * This mess will go away with glibc
+ */
+
+#if defined(__GNUC__)
+#define __KINLINE static __inline__
+#elif defined(__cplusplus)
+#define __KINLINE static __inline__
+#else
+#define __KINLINE static
+#endif
+
+
+/*
+ * Get the next cmsg header
+ *
+ * PLEASE, do not touch this function. If you think, that it is
+ * incorrect, grep kernel sources and think about consequences
+ * before trying to improve it.
+ *
+ * Now it always returns valid, not truncated ancillary object
+ * HEADER. But caller still MUST check, that cmsg->cmsg_len is
+ * inside range, given by msg->msg_controllen before using
+ * ancillary object DATA. --ANK (980731)
+ */
+
+__KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
+ struct cmsghdr *__cmsg)
+{
+ struct cmsghdr * __ptr;
+
+ __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len));
+ if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+ return (struct cmsghdr *)0;
+
+ return __ptr;
+}
+
+__KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
+{
+ return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
+}
+
+/* "Socket"-level control message types: */
+
+#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
+#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
+#define SCM_SECURITY 0x03 /* rw: security label */
+
+struct ucred {
+ __u32 pid;
+ __u32 uid;
+ __u32 gid;
+};
+
+/* Supported address families. */
+#define AF_UNSPEC 0
+#define AF_UNIX 1 /* Unix domain sockets */
+#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+#define AF_INET 2 /* Internet IP Protocol */
+#define AF_AX25 3 /* Amateur Radio AX.25 */
+#define AF_IPX 4 /* Novell IPX */
+#define AF_APPLETALK 5 /* AppleTalk DDP */
+#define AF_NETROM 6 /* Amateur Radio NET/ROM */
+#define AF_BRIDGE 7 /* Multiprotocol bridge */
+#define AF_ATMPVC 8 /* ATM PVCs */
+#define AF_X25 9 /* Reserved for X.25 project */
+#define AF_INET6 10 /* IP version 6 */
+#define AF_ROSE 11 /* Amateur Radio X.25 PLP */
+#define AF_DECnet 12 /* Reserved for DECnet project */
+#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
+#define AF_SECURITY 14 /* Security callback pseudo AF */
+#define AF_KEY 15 /* PF_KEY key management API */
+#define AF_NETLINK 16
+#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */
+#define AF_PACKET 17 /* Packet family */
+#define AF_ASH 18 /* Ash */
+#define AF_ECONET 19 /* Acorn Econet */
+#define AF_ATMSVC 20 /* ATM SVCs */
+#define AF_RDS 21 /* RDS sockets */
+#define AF_SNA 22 /* Linux SNA Project (nutters!) */
+#define AF_IRDA 23 /* IRDA sockets */
+#define AF_PPPOX 24 /* PPPoX sockets */
+#define AF_WANPIPE 25 /* Wanpipe API Sockets */
+#define AF_LLC 26 /* Linux LLC */
+#define AF_CAN 29 /* Controller Area Network */
+#define AF_TIPC 30 /* TIPC sockets */
+#define AF_BLUETOOTH 31 /* Bluetooth sockets */
+#define AF_IUCV 32 /* IUCV sockets */
+#define AF_RXRPC 33 /* RxRPC sockets */
+#define AF_ISDN 34 /* mISDN sockets */
+#define AF_PHONET 35 /* Phonet sockets */
+#define AF_DECT 36 /* DECT sockets */
+#define AF_MAX 37 /* For now.. */
+
+/* Protocol families, same as address families. */
+#define PF_UNSPEC AF_UNSPEC
+#define PF_UNIX AF_UNIX
+#define PF_LOCAL AF_LOCAL
+#define PF_INET AF_INET
+#define PF_AX25 AF_AX25
+#define PF_IPX AF_IPX
+#define PF_APPLETALK AF_APPLETALK
+#define PF_NETROM AF_NETROM
+#define PF_BRIDGE AF_BRIDGE
+#define PF_ATMPVC AF_ATMPVC
+#define PF_X25 AF_X25
+#define PF_INET6 AF_INET6
+#define PF_ROSE AF_ROSE
+#define PF_DECnet AF_DECnet
+#define PF_NETBEUI AF_NETBEUI
+#define PF_SECURITY AF_SECURITY
+#define PF_KEY AF_KEY
+#define PF_NETLINK AF_NETLINK
+#define PF_ROUTE AF_ROUTE
+#define PF_PACKET AF_PACKET
+#define PF_ASH AF_ASH
+#define PF_ECONET AF_ECONET
+#define PF_ATMSVC AF_ATMSVC
+#define PF_RDS AF_RDS
+#define PF_SNA AF_SNA
+#define PF_IRDA AF_IRDA
+#define PF_PPPOX AF_PPPOX
+#define PF_WANPIPE AF_WANPIPE
+#define PF_LLC AF_LLC
+#define PF_CAN AF_CAN
+#define PF_TIPC AF_TIPC
+#define PF_BLUETOOTH AF_BLUETOOTH
+#define PF_IUCV AF_IUCV
+#define PF_RXRPC AF_RXRPC
+#define PF_ISDN AF_ISDN
+#define PF_PHONET AF_PHONET
+#define PF_DECT AF_DECT
+#define PF_MAX AF_MAX
+
+/* Maximum queue length specifiable by listen. */
+#define SOMAXCONN 128
+
+/* Flags we can use with send/ and recv.
+ Added those for 1003.1g not all are supported yet
+ */
+
+#define MSG_OOB 1
+#define MSG_PEEK 2
+#define MSG_DONTROUTE 4
+#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */
+#define MSG_CTRUNC 8
+#define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */
+#define MSG_TRUNC 0x20
+#define MSG_DONTWAIT 0x40 /* Nonblocking io */
+#define MSG_EOR 0x80 /* End of record */
+#define MSG_WAITALL 0x100 /* Wait for a full request */
+#define MSG_FIN 0x200
+#define MSG_SYN 0x400
+#define MSG_CONFIRM 0x800 /* Confirm path validity */
+#define MSG_RST 0x1000
+#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */
+#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */
+#define MSG_MORE 0x8000 /* Sender will send more */
+
+#define MSG_EOF MSG_FIN
+
+#define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exit for file
+ descriptor received through
+ SCM_RIGHTS */
+#if defined(CONFIG_COMPAT)
+#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
+#else
+#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
+#endif
+
+
+/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
+#define SOL_IP 0
+/* #define SOL_ICMP 1 No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */
+#define SOL_TCP 6
+#define SOL_UDP 17
+#define SOL_IPV6 41
+#define SOL_ICMPV6 58
+#define SOL_SCTP 132
+#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */
+#define SOL_RAW 255
+#define SOL_IPX 256
+#define SOL_AX25 257
+#define SOL_ATALK 258
+#define SOL_NETROM 259
+#define SOL_ROSE 260
+#define SOL_DECNET 261
+#define SOL_X25 262
+#define SOL_PACKET 263
+#define SOL_ATM 264 /* ATM layer (cell level) */
+#define SOL_AAL 265 /* ATM Adaption Layer (packet level) */
+#define SOL_IRDA 266
+#define SOL_NETBEUI 267
+#define SOL_LLC 268
+#define SOL_DCCP 269
+#define SOL_NETLINK 270
+#define SOL_TIPC 271
+#define SOL_RXRPC 272
+#define SOL_PPPOL2TP 273
+#define SOL_BLUETOOTH 274
+#define SOL_PNPIPE 275
+#define SOL_RDS 276
+#define SOL_DECT 277
+
+/* IPX options */
+#define IPX_TYPE 1
+
+#endif /* not kernel and not glibc */
+#endif /* _LINUX_SOCKET_H */
diff --git a/include/list.h b/include/list.h
new file mode 100644
index 0000000..75d2921
--- /dev/null
+++ b/include/list.h
@@ -0,0 +1,625 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+#define prefetch(x) ((void)0)
+
+#define LIST_POISON1 ((void *)0x12345678)
+#define LIST_POISON2 ((void *)0x87654321)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void init_list_head(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ init_list_head(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ init_list_head(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ struct list_head *new_first = entry->next;
+ list->next = head->next;
+ list->next->prev = list;
+ list->prev = entry;
+ entry->next = list;
+ head->next = new_first;
+ new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ * and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ *
+ */
+static inline void list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ if (list_empty(head))
+ return;
+ if (list_is_singular(head) &&
+ (head->next != entry && head != entry))
+ return;
+ if (entry == head)
+ init_list_head(list);
+ else
+ __list_cut_position(list, head, entry);
+}
+
+static inline void __list_splice(const struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+
+ first->prev = prev;
+ prev->next = first;
+
+ last->next = next;
+ next->prev = last;
+}
+
+/**
+ * list_splice - join two lists, this is designed for stacks
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head, head->next);
+ init_list_head(list);
+ }
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head->prev, head);
+ init_list_head(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+
+#define init_hlist_head(ptr) ((ptr)->first = NULL)
+
+static inline void init_hlist_node(struct hlist_node *h)
+{
+ h->next = NULL;
+ h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ __hlist_del(n);
+ init_hlist_node(n);
+ }
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if(next->next)
+ next->next->pprev = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = n)
+
+#endif
diff --git a/include/mm.h b/include/mm.h
new file mode 100644
index 0000000..32d1744
--- /dev/null
+++ b/include/mm.h
@@ -0,0 +1,167 @@
+/*
+ * DECT Mobility Management
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _LIBDECT_MM_H
+#define _LIBDECT_MM_H
+
+/**
+ * MM message types
+ */
+enum dect_mm_msg_types {
+ DECT_MM_AUTHENTICATION_REQUEST = 0x40,
+ DECT_MM_AUTHENTICATION_REPLY = 0x41,
+ DECT_MM_KEY_ALLOCATE = 0x42,
+ DECT_MM_AUTHENTICATION_REJECT = 0x43,
+ DECT_MM_ACCESS_RIGHTS_REQUEST = 0x44,
+ DECT_MM_ACCESS_RIGHTS_ACCEPT = 0x45,
+ DECT_MM_ACCESS_RIGHTS_REJECT = 0x47,
+ DECT_MM_ACCESS_RIGHTS_TERMINATE_REQUEST = 0x48,
+ DECT_MM_ACCESS_RIGHTS_TERMINATE_ACCEPT = 0x49,
+ DECT_MM_ACCESS_RIGHTS_TERMINATE_REJECT = 0x4b,
+ DECT_MM_CIPHER_REQUEST = 0x4c,
+ DECT_MM_CIPHER_SUGGEST = 0x4e,
+ DECT_MM_CIPHER_REJECT = 0x4f,
+ DECT_MM_INFO_REQUEST = 0x50,
+ DECT_MM_INFO_ACCEPT = 0x51,
+ DECT_MM_INFO_SUGGEST = 0x52,
+ DECT_MM_INFO_REJECT = 0x53,
+ DECT_MM_LOCATE_REQUEST = 0x54,
+ DECT_MM_LOCATE_ACCEPT = 0x55,
+ DECT_MM_DETACH = 0x56,
+ DECT_MM_LOCATE_REJECT = 0x57,
+ DECT_MM_IDENTITY_REQUEST = 0x58,
+ DECT_MM_IDENTITY_REPLY = 0x59,
+ DECT_MM_TEMPORARY_IDENTITY_ASSIGN = 0x5c,
+ DECT_MM_TEMPORARY_IDENTITY_ASSIGN_ACK = 0x5d,
+ DECT_MM_TEMPORARY_IDENTITY_ASSIGN_REJ = 0x5f,
+};
+
+struct dect_mm_access_rights_accept_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_access_rights_reject_msg {
+ struct dect_msg_common common;
+ struct dect_ie_reject_reason *reject_reason;
+ struct dect_ie_duration *duration;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_mm_access_rights_request_msg {
+ struct dect_msg_common common;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_auth_type *auth_type;
+ struct dect_ie_cipher_info *cipher_info;
+ struct dect_ie_setup_capability *setup_capability;
+ struct dect_ie_terminal_capability *terminal_capability;
+ struct dect_ie_iwu_to_iwu *iwu_to_iwu;
+ struct dect_ie_model_identifier *model_identifier;
+ struct dect_ie_codec_list *codec_list;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_mm_access_rights_terminate_accept_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_access_rights_terminate_reject_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_access_rights_terminate_request_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_authentication_reject_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_authentication_reply_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_authentication_request_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_cipher_reject_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_cipher_request_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_cipher_suggest_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_detach_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_identity_reply_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_identity_request_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_key_allocate_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_locate_accept_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_locate_reject_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_locate_request_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_info_accept_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_info_reject_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_info_request_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_info_suggest_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_temporary_identity_assign_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_temporary_identity_assign_ack_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_temporary_identity_assign_rej_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_iwu_msg {
+ struct dect_msg_common common;
+};
+
+struct dect_mm_notify_msg {
+ struct dect_msg_common common;
+};
+
+#endif /* _LIBDECT_MM_H */
diff --git a/include/netlink.h b/include/netlink.h
new file mode 100644
index 0000000..4898bb5
--- /dev/null
+++ b/include/netlink.h
@@ -0,0 +1,7 @@
+#ifndef _DECT_NETLINK_H
+#define _DECT_NETLINK_H
+
+extern int dect_netlink_init(struct dect_handle *dh);
+extern void dect_netlink_exit(struct dect_handle *dh);
+
+#endif /* _DECT_NETLINK_H */
diff --git a/include/s_fmt.h b/include/s_fmt.h
new file mode 100644
index 0000000..ed3d5cf
--- /dev/null
+++ b/include/s_fmt.h
@@ -0,0 +1,377 @@
+#ifndef _DECT_S_FMT_H
+#define _DECT_S_FMT_H
+
+#include <assert.h>
+#include <identities.h>
+
+/*
+ * S-Format message header
+ */
+
+#define DECT_S_HDR_SIZE 2
+
+/* Transaction Identifier (TI) element */
+#define DECT_S_TI_F_FLAG 0x80
+
+#define DECT_S_TI_TV_MASK 0x70
+#define DECT_S_TI_TV_SHIFT 4
+
+#define DECT_S_TI_TV_EXT_FLAG 0x08
+
+/* Protocol Descriminator (PD) element */
+#define DECT_S_PD_MASK 0x0f
+
+/**
+ * @DECT_S_PD_LCE: Link Control Entity (LCE) messages
+ * @DECT_S_PD_CC: Call Control (CC) messages
+ * @DECT_S_PD_CISS: Call Independant Supplementary Services (CISS) messages
+ * @DECT_S_PD_MM: Mobility Management (MM) messages
+ * @DECT_S_PD_CLMS: ConnectionLess Message Service (CLMS) messages
+ * @DECT_S_PD_COMS: Connection Orentied Message Service (COMS) messages
+ * @DECT_S_PD_UNKNOWN: Unknown protocol entity (bit 8)
+ */
+enum dect_s_pd_values {
+ DECT_S_PD_LCE = 0x0,
+ DECT_S_PD_CC = 0x3,
+ DECT_S_PD_CISS = 0x4,
+ DECT_S_PD_MM = 0x5,
+ DECT_S_PD_CLMS = 0x6,
+ DECT_S_PD_COMS = 0x7,
+ DECT_S_PD_UNKNOWN = 0x8,
+ __DECT_S_PD_MAX
+};
+#define DECT_S_PD_MAX (__DECT_S_PD_MAX - 1)
+
+/* Message type element */
+#define DECT_S_PD_MSG_TYPE_MASK 0x7f
+
+/* CLMS message types */
+enum dect_clms_msg_types {
+ DECT_CLMS_VARIABLE = 0x1,
+};
+
+/*
+ * Information elements
+ */
+
+#define DECT_SFMT_IE_FIXED_LEN 0x80
+#define DECT_SFMT_IE_FIXED_ID_MASK 0x70
+#define DECT_SFMT_IE_FIXED_ID_SHIFT 4
+#define DECT_SFMT_IE_FIXED_VAL_MASK 0x0f
+
+enum dect_sfmt_single_octet_ies {
+ S_SO_IE_RESERVED = (0x00 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
+ S_SO_IE_SHIFT = (0x01 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
+ S_SO_IE_EXT_PREFIX = (0x02 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
+ S_SO_IE_REPEAT_INDICATOR = (0x05 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
+ S_SO_IE_DOUBLE_OCTET_ELEMENT = (0x06 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
+};
+
+enum dect_sfmt_single_octet_ext_ies {
+ S_SE_IE_SENDING_COMPLETE = 0x1 | S_SO_IE_EXT_PREFIX,
+ S_SE_IE_DELIMITER_REQUEST = 0x2 | S_SO_IE_EXT_PREFIX,
+ S_SE_IE_USE_TPUI = 0x3 | S_SO_IE_EXT_PREFIX,
+};
+
+enum dect_sfmt_double_octet_ies {
+ S_DO_IE_BASIC_SERVICE = 0x0 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+ S_DO_IE_RELEASE_REASON = 0x2 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+ S_DO_IE_SIGNAL = 0x4 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+ S_DO_IE_TIMER_RESTART = 0x5 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+ S_DO_IE_TEST_HOOK_CONTROL = 0x6 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+ S_DO_IE_SINGLE_DISPLAY = 0x8 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+ S_DO_IE_SINGLE_KEYPAD = 0x9 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+ S_DO_IE_RESERVED = 0xf | S_SO_IE_DOUBLE_OCTET_ELEMENT,
+};
+
+enum dect_sfmt_variable_length_ies {
+ S_VL_IE_INFO_TYPE = 0x01,
+ S_VL_IE_IDENTITY_TYPE = 0x02,
+ S_VL_IE_PORTABLE_IDENTITY = 0x05,
+ S_VL_IE_FIXED_IDENTITY = 0x06,
+ S_VL_IE_LOCATION_AREA = 0x07,
+ S_VL_IE_NWK_ASSIGNED_IDENTITY = 0x09,
+ S_VL_IE_AUTH_TYPE = 0x0a,
+ S_VL_IE_ALLOCATION_TYPE = 0x0b,
+ S_VL_IE_RAND = 0x0c,
+ S_VL_IE_RES = 0x0d,
+ S_VL_IE_RS = 0x0e,
+ S_VL_IE_IWU_ATTRIBUTES = 0x12,
+ S_VL_IE_CALL_ATTRIBUTES = 0x13,
+ S_VL_IE_SERVICE_CHANGE_INFO = 0x16,
+ S_VL_IE_CONNECTION_ATTRIBUTES = 0x17,
+ S_VL_IE_CIPHER_INFO = 0x19,
+ S_VL_IE_CALL_IDENTITY = 0x1a,
+ S_VL_IE_CONNECTION_IDENTITY = 0x1b,
+ S_VL_IE_FACILITY = 0x1c,
+ S_VL_IE_PROGRESS_INDICATOR = 0x1e,
+ S_VL_IE_MMS_GENERIC_HEADER = 0x20,
+ S_VL_IE_MMS_OBJECT_HEADER = 0x21,
+ S_VL_IE_MMS_EXTENDED_HEADER = 0x22,
+ S_VL_IE_TIME_DATE = 0x23,
+ S_VL_IE_MULTI_DISPLAY = 0x28,
+ S_VL_IE_MULTI_KEYPAD = 0x2c,
+ S_VL_IE_FEATURE_ACTIVATE = 0x38,
+ S_VL_IE_FEATURE_INDICATE = 0x39,
+ S_VL_IE_NETWORK_PARAMETER = 0x41,
+ S_VL_IE_EXT_HO_INDICATOR = 0x42,
+ S_VL_IE_ZAP_FIELD = 0x52,
+ S_VL_IE_SERVICE_CLASS = 0x54,
+ S_VL_IE_KEY = 0x56,
+ S_VL_IE_REJECT_REASON = 0x60,
+ S_VL_IE_SETUP_CAPABILITY = 0x62,
+ S_VL_IE_TERMINAL_CAPABILITY = 0x63,
+ S_VL_IE_END_TO_END_COMPATIBILITY = 0x64,
+ S_VL_IE_RATE_PARAMETERS = 0x65,
+ S_VL_IE_TRANSIT_DELAY = 0x66,
+ S_VL_IE_WINDOW_SIZE = 0x67,
+ S_VL_IE_CALLING_PARTY_NUMBER = 0x6c,
+ S_VL_IE_CALLING_PARTY_NAME = 0x6d,
+ S_VL_IE_CALLED_PARTY_NUMBER = 0x70,
+ S_VL_IE_CALLED_PARTY_SUBADDR = 0x71,
+ S_VL_IE_DURATION = 0x72,
+ S_VL_IE_SEGMENTED_INFO = 0x75,
+ S_VL_IE_ALPHANUMERIC = 0x76,
+ S_VL_IE_IWU_TO_IWU = 0x77,
+ S_VL_IE_MODEL_IDENTIFIER = 0x78,
+ S_VL_IE_IWU_PACKET = 0x7a,
+ S_VL_IE_ESCAPE_TO_PROPRIETARY = 0x7b,
+ S_VL_IE_CODEC_LIST = 0x7c,
+ S_VL_IE_EVENTS_NOTIFICATION = 0x7d,
+ S_VL_IE_CALL_INFORMATION = 0x7e,
+ S_VL_IE_ESCAPE_FOR_EXTENSION = 0x7f,
+ __S_VL_IE_MAX
+};
+
+/* Repeat indicator */
+
+/* Basic service */
+
+#define DECT_BASIC_SERVICE_CALL_CLASS_MASK 0xf0
+#define DECT_BASIC_SERVICE_CALL_CLASS_SHIFT 4
+
+#define DECT_BASIC_SERVICE_SERVICE_MASK 0x0f
+
+/* Single display IE */
+
+/* Single keypad IE */
+
+/* Release reason */
+
+/* Allocation type IE */
+
+/* Alphanumeric IE */
+
+/* Auth type IE */
+
+/* Call attributes IE */
+
+/* Call identity IE */
+
+/* Called party number IE */
+
+/* Called party subaddress IE */
+
+/* Calling party number IE */
+
+/* Cipher info IE */
+
+/* Connection attributes IE */
+
+/* Connection identity IE */
+
+/* Duration IE */
+
+/* End-to-end compatibility IE */
+
+/* Facility IE */
+
+/* Feature activate IE */
+
+/* Feature indicate IE */
+
+/* Fixed identity IE */
+
+#define S_VL_IE_FIXED_IDENTITY_MIN_SIZE 2
+
+#define S_VL_IE_FIXED_IDENTITY_TYPE_MASK 0x7f
+#define S_VL_IE_FIXED_IDENTITY_LENGTH_MASK 0x7f
+
+/* Identity type IE */
+
+/* Info type IE */
+
+/* InterWorking Unit (IWU) attributes IE */
+
+/* IWU packet IE */
+
+/* IWU to IWU IE */
+
+/* Key IE */
+
+/* Location area IE */
+
+/* Multi-display IE */
+
+/* Multi-keypad IE */
+
+/* NetWorK (NWK) assigned identity IE */
+
+/* Network parameter IE */
+
+/* Portable identity IE */
+
+#define S_VL_IE_PORTABLE_IDENTITY_MIN_SIZE 2
+
+#define S_VL_IE_PORTABLE_IDENTITY_TYPE_MASK 0x7f
+#define S_VL_IE_PORTABLE_IDENTITY_LENGTH_MASK 0x7f
+
+/* IPUI */
+
+#define IPUI_BITS_PER_DIGIT 4
+#define IPUI_PUT_PSTN_ISDN_NUMBER_MAX_DIGITS 60
+
+#define IPUI_PUT_PRIVATE_NUMBER_MAX_LEN 60
+
+/* Progress indicator IE */
+
+#define DECT_SFMT_IE_PROGRESS_INDICATOR_LOCATION_MASK 0x0f
+
+/* RAND IE */
+
+/* Rate parameters IE */
+
+/* Reject reason IE */
+
+/* RES IE */
+
+/* RS IE */
+
+/* Segmented info IE */
+
+/* Service change info IE */
+
+/* Service class IE */
+
+/* Setup capability IE */
+
+/* Terminal capability IE */
+
+/* Transit delay IE */
+
+/* Window size IE */
+
+/* ZAP field IE */
+
+/* Escape to proprietary IE */
+
+#define DECT_ESC_TO_PROPRIETARY_IE_DESC_TYPE_MASK 0x7f
+#define DECT_ESC_TO_PROPRIETARY_IE_DESC_EMC 1
+
+/* Model identifier IE */
+
+/* MMS Generic Header IE */
+
+/* MMS Object Header IE */
+
+/* MMS Extended Header IE */
+
+/* Time-Data IE */
+
+/* Ext h/o indicator IE */
+
+/* Authentication Reject Parameter IE */
+
+/* Calling party Name IE */
+
+/* Codec List IE */
+
+/* Events notification IE */
+
+/* Call information IE */
+
+enum dect_sfmt_ie_status {
+ DECT_SFMT_IE_NONE,
+ DECT_SFMT_IE_OPTIONAL,
+ DECT_SFMT_IE_MANDATORY
+};
+
+enum dect_sfmt_ie_flags {
+ DECT_SFMT_IE_REPEAT = 0x1,
+ DECT_SFMT_IE_EITHER = 0x2,
+ DECT_SFMT_IE_END = 0x4,
+};
+
+/**
+ * struct dect_sfmt_ie_desc - S-Format IE description
+ *
+ * @offset: offset of corresponding S-Format IE storage
+ * @type: IE type
+ * @f_p: Status in direction FP->PP
+ * @p_f: Status in direction PP->FP
+ * @flags: Global flags
+ */
+struct dect_sfmt_ie_desc {
+ uint16_t type;
+ enum dect_sfmt_ie_status f_p:8;
+ enum dect_sfmt_ie_status p_f:8;
+ uint8_t flags;
+};
+
+#define DECT_SFMT_IE(_type, _f_p, _p_f, _flags) { \
+ .type = (_type), \
+ .f_p = DECT_SFMT_ ## _f_p, \
+ .p_f = DECT_SFMT_ ## _p_f, \
+ .flags = (_flags), \
+}
+
+#define DECT_SFMT_IE_END_MSG { \
+ .flags = DECT_SFMT_IE_END, \
+}
+
+
+struct dect_sfmt_ie {
+ uint8_t *data;
+ uint16_t id;
+ uint8_t len;
+};
+
+/**
+ * enum dect_sfmt_error - S-Format message parsing/construction state
+ *
+ * @DECT_SFMT_OK: No error
+ * @DECT_SFMT_MANDATORY_IE_MISSING: A mandatory IE was missing
+ * @DECT_SFMT_MANDATORY_IE_ERROR: A mandatory IE had an internal structural error
+ * @DECT_SFMT_INVALID_IE: An invalid IE was passed to message construction
+ */
+enum dect_sfmt_error {
+ DECT_SFMT_OK = 0,
+ DECT_SFMT_MANDATORY_IE_MISSING = -1,
+ DECT_SFMT_MANDATORY_IE_ERROR = -2,
+ DECT_SFMT_INVALID_IE = -3,
+};
+
+/**
+ * struct dect_msg_common - Common dummy msg structure to avoid casts
+ *
+ * @ie: First IE
+ */
+struct dect_msg_common {
+ struct dect_ie_common *ie[0];
+};
+
+struct dect_msg_buf;
+extern 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);
+extern 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);
+
+extern void dect_msg_free(const struct dect_handle *dh,
+ const struct dect_sfmt_ie_desc *desc,
+ struct dect_msg_common *msg);
+
+#endif /* _DECT_S_FMT_H */
diff --git a/include/ss.h b/include/ss.h
new file mode 100644
index 0000000..fe5138f
--- /dev/null
+++ b/include/ss.h
@@ -0,0 +1,70 @@
+/*
+ * DECT Supplementary Services (SS)
+ *
+ * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
+ */
+
+#ifndef _DECT_SS_H
+#define _DECT_SS_H
+
+/**
+ * Call Independant Supplementary Services messages types
+ */
+enum dect_ciss_msg_types {
+ CISS_RELEASE_COM = 0x5a,
+ CISS_FACILITY = 0x62,
+ CISS_REGISTER = 0x64,
+};
+
+struct dect_ciss_release_com_msg {
+ struct dect_msg_common common;
+ struct dect_ie_release_reason *release_reason;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+struct dect_ciss_facility_msg {
+ struct dect_msg_common common;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_repeat_indicator iwu_to_iwu;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+ struct dect_ie_time_date *time_date;
+ struct dect_ie_events_notification *events_notification;
+ struct dect_ie_call_information *call_information;
+};
+
+struct dect_ciss_register_msg {
+ struct dect_msg_common common;
+ struct dect_ie_portable_identity *portable_identity;
+ struct dect_ie_repeat_indicator facility;
+ struct dect_ie_display *display;
+ struct dect_ie_keypad *keypad;
+ struct dect_ie_feature_activate *feature_activate;
+ struct dect_ie_feature_indicate *feature_indicate;
+ struct dect_ie_escape_to_proprietary *escape_to_proprietary;
+};
+
+extern void dect_clss_rcv(struct dect_handle *dh, struct dect_msg_buf *mb);
+
+/**
+ * Call Related Supplementary Services messages types
+ */
+enum dect_crss_msg_types {
+ CRSS_HOLD = 0x24,
+ CRSS_HOLD_ACK = 0x28,
+ CRSS_HOLD_REJECT = 0x30,
+ CRSS_RETRIEVE = 0x31,
+ CRSS_RETRIEVE_ACK = 0x33,
+ CRSS_RETRIEVE_REJECT = 0x37,
+ CRSS_FACILITY = 0x62,
+};
+
+#endif
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..e008bc8
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,70 @@
+#ifndef _UITLS_H
+#define _UTILS_H
+
+#include <assert.h>
+
+#ifndef AF_DECT
+#define AF_DECT 36
+#endif
+
+#define __init __attribute__((constructor))
+#define __exit __attribute__((destructor))
+#define __must_check __attribute__((warn_unused_result))
+#define __noreturn __attribute__((__noreturn__))
+#define __fmtstring(x, y) __attribute__((format(printf, x, y)))
+#define __aligned(x) __attribute__((aligned(x)))
+#define __packed __attribute__((packed))
+
+extern void *dect_malloc(const struct dect_handle *dh, size_t size);
+extern void *dect_zalloc(const struct dect_handle *dh, size_t size);
+extern void dect_free(const struct dect_handle *dh, void *ptr);
+
+extern struct dect_timer *dect_alloc_timer(const struct dect_handle *dh);
+extern void dect_start_timer(const struct dect_handle *dh,
+ struct dect_timer *timer, unsigned int timeout);
+extern void dect_stop_timer(const struct dect_handle *dh, struct dect_timer *timer);
+
+struct dect_fd *dect_alloc_fd(const struct dect_handle *dh);
+extern void dect_close(const struct dect_handle *dh, struct dect_fd *dfd);
+
+extern void dect_debug(const char *fmt, ...) __fmtstring(1, 2);
+extern void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size);
+
+#include <sys/socket.h> // FIXME: socklen_t
+extern struct dect_fd *dect_socket(const struct dect_handle *dh,
+ int type, int protocol);
+extern struct dect_fd *dect_accept(const struct dect_handle *dh,
+ const struct dect_fd *dfd,
+ struct sockaddr *addr, socklen_t len);
+
+extern int dect_register_fd(const struct dect_handle *dh, struct dect_fd *dfd,
+ uint32_t events);
+extern void dect_unregister_fd(const struct dect_handle *dh, struct dect_fd *dfd);
+
+#define BUG() assert(0)
+
+/* Force a compilation error if condition is true */
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
+
+#define __must_be_array(a) \
+ BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
+
+#define array_size(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+#define field_sizeof(t, f) (sizeof(((t *)NULL)->f))
+
+#define div_round_up(n, d) (((n) + (d) - 1) / (d))
+
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+#endif /* _UTILS_H */
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..d4744f0
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,269 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+#
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
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;
+}