From 0406a88b39a9c978d47ababf9fd93d9e244e1a4a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 6 May 2009 18:41:57 +0200 Subject: Import libdect Signed-off-by: Patrick McHardy --- .gitignore | 18 + Makefile.defs.in | 42 ++ Makefile.in | 5 + Makefile.rules.in | 108 ++++ autogen.sh | 4 + configure.ac | 74 +++ doc/Doxyfile.in | 1417 +++++++++++++++++++++++++++++++++++++++++++++ doc/Makefile.in | 4 + example/.gitignore | 1 + example/Makefile.in | 8 + example/audio.c | 95 +++ example/common.h | 23 + example/event_ops.c | 115 ++++ example/mm | Bin 0 -> 39435 bytes example/mm.c | 74 +++ example/test.c | 294 ++++++++++ include/Makefile.in | 3 + include/b_fmt.h | 48 ++ include/cc.h | 333 +++++++++++ include/coms.h | 15 + include/dect/cc.h | 246 ++++++++ include/dect/identities.h | 169 ++++++ include/dect/ie.h | 767 ++++++++++++++++++++++++ include/dect/keypad.h | 15 + include/dect/libdect.h | 134 +++++ include/dect/mm.h | 38 ++ include/dect/terminal.h | 70 +++ include/dect/utils.h | 8 + include/identities.h | 121 ++++ include/lce.h | 197 +++++++ include/libdect.h | 35 ++ include/linux/dect.h | 76 +++ include/linux/socket.h | 306 ++++++++++ include/list.h | 625 ++++++++++++++++++++ include/mm.h | 167 ++++++ include/netlink.h | 7 + include/s_fmt.h | 377 ++++++++++++ include/ss.h | 70 +++ include/utils.h | 70 +++ install-sh | 269 +++++++++ src/.gitignore | 1 + src/Makefile.in | 19 + src/cc.c | 1128 ++++++++++++++++++++++++++++++++++++ src/ccitt-adpcm/README | 94 +++ src/ccitt-adpcm/decode.c | 113 ++++ src/ccitt-adpcm/encode.c | 119 ++++ src/ccitt-adpcm/g711.c | 285 +++++++++ src/ccitt-adpcm/g721.c | 173 ++++++ src/ccitt-adpcm/g723_24.c | 158 +++++ src/ccitt-adpcm/g723_40.c | 178 ++++++ src/ccitt-adpcm/g72x.c | 565 ++++++++++++++++++ src/ccitt-adpcm/g72x.h | 148 +++++ src/dsaa.c | 211 +++++++ src/identities.c | 182 ++++++ src/keypad.c | 80 +++ src/lce.c | 790 +++++++++++++++++++++++++ src/libdect.c | 81 +++ src/mm.c | 154 +++++ src/netlink.c | 139 +++++ src/s_msg.c | 991 +++++++++++++++++++++++++++++++ src/ss.c | 49 ++ src/utils.c | 142 +++++ 62 files changed, 12248 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile.defs.in create mode 100644 Makefile.in create mode 100644 Makefile.rules.in create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 doc/Doxyfile.in create mode 100644 doc/Makefile.in create mode 100644 example/.gitignore create mode 100644 example/Makefile.in create mode 100644 example/audio.c create mode 100644 example/common.h create mode 100644 example/event_ops.c create mode 100755 example/mm create mode 100644 example/mm.c create mode 100644 example/test.c create mode 100644 include/Makefile.in create mode 100644 include/b_fmt.h create mode 100644 include/cc.h create mode 100644 include/coms.h create mode 100644 include/dect/cc.h create mode 100644 include/dect/identities.h create mode 100644 include/dect/ie.h create mode 100644 include/dect/keypad.h create mode 100644 include/dect/libdect.h create mode 100644 include/dect/mm.h create mode 100644 include/dect/terminal.h create mode 100644 include/dect/utils.h create mode 100644 include/identities.h create mode 100644 include/lce.h create mode 100644 include/libdect.h create mode 100644 include/linux/dect.h create mode 100644 include/linux/socket.h create mode 100644 include/list.h create mode 100644 include/mm.h create mode 100644 include/netlink.h create mode 100644 include/s_fmt.h create mode 100644 include/ss.h create mode 100644 include/utils.h create mode 100755 install-sh create mode 100644 src/.gitignore create mode 100644 src/Makefile.in create mode 100644 src/cc.c create mode 100644 src/ccitt-adpcm/README create mode 100644 src/ccitt-adpcm/decode.c create mode 100644 src/ccitt-adpcm/encode.c create mode 100644 src/ccitt-adpcm/g711.c create mode 100644 src/ccitt-adpcm/g721.c create mode 100644 src/ccitt-adpcm/g723_24.c create mode 100644 src/ccitt-adpcm/g723_40.c create mode 100644 src/ccitt-adpcm/g72x.c create mode 100644 src/ccitt-adpcm/g72x.h create mode 100644 src/dsaa.c create mode 100644 src/identities.c create mode 100644 src/keypad.c create mode 100644 src/lce.c create mode 100644 src/libdect.c create mode 100644 src/mm.c create mode 100644 src/netlink.c create mode 100644 src/s_msg.c create mode 100644 src/ss.c create mode 100644 src/utils.c 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 ]) +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 , where is the value of +# the FILE_VERSION_FILTER tag, and 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 , where +# is the value of the INPUT_FILTER tag, and 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 +#include +#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 +#include +#include + +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 +#include +#include +#include +#include + +#include +#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 Binary files /dev/null and b/example/mm 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 +#include +#include +#include +#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, ¶m); +} + +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 +#include +#include +#include +#include +#include + +#include +#include +#include +#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, ¶m); +} + +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 + */ + +#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 + */ + +#ifndef _LIBDECT_DECT_CC_H +#define _LIBDECT_DECT_CC_H + +#include + +/** + * 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 + */ + +#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 + */ + +#ifndef _LIBDECT_DECT_IE_H +#define _LIBDECT_DECT_IE_H + +#include +#include +#include + +/** + * 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 + */ + +#ifndef _LIBDECT_DECT_LIBDECT_H +#define _LIBDECT_DECT_LIBDECT_H + +#include +#include +#include + +#include +#include +#include + +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 + */ + +#ifndef _LIBDECT_DECT_MM_H +#define _LIBDECT_DECT_MM_H + +#include + +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 + */ + +#ifndef _DECT_LCE_H +#define _DECT_LCE_H + +#include +#include +#include +#include +#include + +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 +#include +#include + +/** + * 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 +#include + +/* 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 /* arch-dependent defines */ +#include /* the SIOCxxx I/O controls */ +#include /* iovec support */ +#include /* 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 + +#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 + */ + +#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 +#include + +/* + * 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 + */ + +#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 + +#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 // 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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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, ¶m); + + 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 *)¶m->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 *)¶m->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, ¶m); +} + +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, ¶m); +} + +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, ¶m); +} + +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, ¶m); +} + +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, ¶m); + } + + 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, ¶m); +} + +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(¶m.iwu_attributes, &msg->iwu_attributes); + dect_ie_list_move(¶m.facility, &msg->facility); + dect_ie_list_move(¶m.progress_indicator, &msg->progress_indicator); + + dh->ops->cc_ops->mncc_setup_ind(dh, call, ¶m); +} + +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] outfile + decode [-3|4|5] [-a|u|l] 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 g721file + + # Read 40Kbps G.723 and output A-law + decode -5 -a alawfile + + # Compress and then decompress u-law data using 24Kbps G.723 + encode -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 +#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 +#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 +#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 +#include +#include + +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 + * + * 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 +#include +#include +#include +#include + +#include +#include +#include + + +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 + * + * 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 +#include +#include +#include +#include + +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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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(<e->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(<e->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 + * + * 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 +#include +#include +#include + +#include +#include +#include +#include + +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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +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 + * + * 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +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 + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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; +} -- cgit v1.2.3