Import libdect
Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
commit
0406a88b39
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
SUBDIRS += include
|
||||
SUBDIRS += src
|
||||
SUBDIRS += example
|
||||
|
||||
include Makefile.rules
|
|
@ -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="$@/"
|
|
@ -0,0 +1,4 @@
|
|||
#! /bin/sh
|
||||
|
||||
autoreconf -fi;
|
||||
rm -Rf autom4te*.cache config.h.in~
|
|
@ -0,0 +1,74 @@
|
|||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
|
||||
AC_COPYRIGHT([Copyright (c) 2008 Patrick McHardy <kaber@trash.net>])
|
||||
AC_INIT([libdect], [0.0.1], [kaber@trash.net])
|
||||
AC_DEFINE([RELEASE_NAME], ["libdect"], [Release name])
|
||||
|
||||
AC_CONFIG_SRCDIR([src/s_msg.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
||||
AC_DEFINE([_GNU_SOURCE], [], [Enable various GNU extensions])
|
||||
AC_DEFINE([_STDC_FORMAT_MACROS], [], [printf-style format macros])
|
||||
|
||||
AC_ARG_ENABLE([debug],
|
||||
AS_HELP_STRING([--enable-debug], [Enable debugging]),
|
||||
[CONFIG_DEBUG="$(echo $enableval | cut -b1)"],
|
||||
[CONFIG_DEBUG="y"])
|
||||
AC_SUBST([CONFIG_DEBUG])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_MKDIR_P
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([nl], [nl_socket_alloc], ,
|
||||
AC_MSG_ERROR([No suitable version of libnl found]))
|
||||
|
||||
AC_CHECK_LIB([nl-dect], [nl_dect_cluster_alloc], ,
|
||||
AC_MSG_ERROR([No suitable version of libnl-dect found]))
|
||||
|
||||
AC_CHECK_LIB([event], [event_init], ,
|
||||
AC_MSG_ERROR([No suitable version of libevent found]))
|
||||
|
||||
AC_CHECK_LIB([SDL], [SDL_OpenAudio], ,
|
||||
AC_MSG_ERROR([No suitable version of libsdl found]))
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_ASSERT
|
||||
AC_CHECK_HEADERS([fcntl.h inttypes.h libintl.h limits.h malloc.h \
|
||||
stddef.h stdint.h stdlib.h string.h unistd.h], ,
|
||||
AC_MSG_ERROR([Header file not found]))
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_INT8_T
|
||||
AC_TYPE_INT16_T
|
||||
AC_TYPE_INT32_T
|
||||
AC_TYPE_INT64_T
|
||||
AC_TYPE_UINT8_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_REALLOC
|
||||
AC_CHECK_FUNCS([memmove memset strchr strdup strerror strtoull])
|
||||
|
||||
AC_CONFIG_FILES([Makefile Makefile.defs Makefile.rules])
|
||||
AC_CONFIG_FILES([include/Makefile])
|
||||
AC_CONFIG_FILES([src/Makefile])
|
||||
AC_CONFIG_FILES([example/Makefile])
|
||||
AC_CONFIG_FILES([doc/Makefile doc/Doxyfile])
|
||||
AC_OUTPUT
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,4 @@
|
|||
all: doxygen
|
||||
|
||||
doxygen:
|
||||
$(DOXYGEN) $(SUBDIR)Doxyfile
|
|
@ -0,0 +1 @@
|
|||
test
|
|
@ -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
|
|
@ -0,0 +1,95 @@
|
|||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_audio.h>
|
||||
#include "common.h"
|
||||
|
||||
void dect_audio_queue(struct dect_audio_handle *ah, struct dect_msg_buf *mb)
|
||||
{
|
||||
SDL_LockAudio();
|
||||
list_add_tail(&mb->list, &ah->queue);
|
||||
SDL_UnlockAudio();
|
||||
}
|
||||
|
||||
static void dect_decode_g721(struct g72x_state *codec,
|
||||
int16_t *dst, const uint8_t *src,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len * 2; i += 2) {
|
||||
dst[i + 0] = g721_decoder(src[i / 2] >> 4,
|
||||
AUDIO_ENCODING_LINEAR, codec);
|
||||
dst[i + 1] = g721_decoder(src[i / 2] & 0x0f,
|
||||
AUDIO_ENCODING_LINEAR, codec);
|
||||
}
|
||||
}
|
||||
|
||||
static void dect_audio_dequeue(void *data, uint8_t *stream, int len)
|
||||
{
|
||||
struct dect_audio_handle *ah = data;
|
||||
struct dect_msg_buf *mb;
|
||||
int copy;
|
||||
|
||||
len /= 4;
|
||||
while (1) {
|
||||
if (list_empty(&ah->queue))
|
||||
goto underrun;
|
||||
mb = list_first_entry(&ah->queue, struct dect_msg_buf, list);
|
||||
copy = mb->len;
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
|
||||
dect_decode_g721(&ah->codec, (int16_t *)stream, mb->data, copy);
|
||||
dect_mbuf_pull(mb, copy);
|
||||
if (mb->len == 0) {
|
||||
list_del(&mb->list);
|
||||
free(mb);
|
||||
}
|
||||
|
||||
len -= copy;
|
||||
if (len == 0)
|
||||
return;
|
||||
stream += 4 * copy;
|
||||
}
|
||||
|
||||
underrun:
|
||||
printf("audio underrun, missing %u bytes\n", len * 4);
|
||||
memset(stream, 0, len * 4);
|
||||
}
|
||||
|
||||
struct dect_audio_handle *dect_audio_open(void)
|
||||
{
|
||||
struct dect_audio_handle *ah;
|
||||
SDL_AudioSpec spec = {
|
||||
.freq = 8000,
|
||||
.format = AUDIO_S16SYS,
|
||||
.channels = 1,
|
||||
.samples = 512,
|
||||
.callback = dect_audio_dequeue,
|
||||
};
|
||||
|
||||
ah = malloc(sizeof(*ah));
|
||||
if (ah == NULL)
|
||||
goto err1;
|
||||
init_list_head(&ah->queue);
|
||||
g72x_init_state(&ah->codec);
|
||||
|
||||
spec.userdata = ah;
|
||||
if (SDL_OpenAudio(&spec, NULL) < 0)
|
||||
goto err2;
|
||||
SDL_PauseAudio(0);
|
||||
|
||||
return ah;
|
||||
|
||||
err2:
|
||||
free(ah);
|
||||
err1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __init dect_audio_init(void)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
|
||||
fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef _DECT_TEST_COMMON_H
|
||||
#define _DECT_TEST_COMMON_H
|
||||
|
||||
#include <libdect.h>
|
||||
#include <utils.h>
|
||||
#include <list.h>
|
||||
|
||||
extern struct dect_handle *dh;
|
||||
extern int dect_event_ops_init(struct dect_ops *ops);
|
||||
extern void dect_event_loop(void);
|
||||
extern void dect_event_ops_cleanup(void);
|
||||
|
||||
#include "../src/ccitt-adpcm/g72x.h"
|
||||
|
||||
struct dect_audio_handle {
|
||||
struct g72x_state codec;
|
||||
struct list_head queue;
|
||||
};
|
||||
|
||||
extern struct dect_audio_handle *dect_audio_open(void);
|
||||
extern void dect_audio_queue(struct dect_audio_handle *ah, struct dect_msg_buf *mb);
|
||||
|
||||
#endif /* _DECT_TEST_COMMON_H */
|
|
@ -0,0 +1,115 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <event.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include "common.h"
|
||||
|
||||
struct dect_handle *dh;
|
||||
|
||||
static void event_callback(int fd, short mask, void *data)
|
||||
{
|
||||
struct dect_fd *dfd = data;
|
||||
uint32_t events;
|
||||
|
||||
events = 0;
|
||||
if (mask & EV_READ)
|
||||
events |= DECT_FD_READ;
|
||||
if (mask & EV_WRITE)
|
||||
events |= DECT_FD_WRITE;
|
||||
|
||||
dfd->callback(dh, dfd, events);
|
||||
}
|
||||
|
||||
static int register_fd(const struct dect_handle *dh, struct dect_fd *dfd,
|
||||
uint32_t events)
|
||||
{
|
||||
struct event *ev = (struct event *)dfd->priv;
|
||||
unsigned short mask;
|
||||
|
||||
mask = EV_PERSIST;
|
||||
if (events & DECT_FD_READ)
|
||||
mask |= EV_READ;
|
||||
if (events & DECT_FD_WRITE)
|
||||
mask |= EV_WRITE;
|
||||
|
||||
event_set(ev, dfd->fd, mask, event_callback, dfd);
|
||||
event_add(ev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unregister_fd(const struct dect_handle *dh, struct dect_fd *dfd)
|
||||
{
|
||||
struct event *ev = (struct event *)dfd->priv;
|
||||
|
||||
event_del(ev);
|
||||
}
|
||||
|
||||
static void timer_expire(int fd, short mask, void *data)
|
||||
{
|
||||
struct dect_timer *timer = data;
|
||||
|
||||
timer->callback(dh, timer);
|
||||
}
|
||||
|
||||
static void start_timer(const struct dect_handle *dh,
|
||||
struct dect_timer *timer,
|
||||
const struct timeval *tv)
|
||||
{
|
||||
struct event *ev = (struct event *)timer->priv;
|
||||
|
||||
evtimer_set(ev, timer_expire, timer);
|
||||
evtimer_add(ev, (struct timeval *)tv);
|
||||
}
|
||||
|
||||
static void stop_timer(const struct dect_handle *dh, struct dect_timer *timer)
|
||||
{
|
||||
struct event *ev = (struct event *)timer->priv;
|
||||
|
||||
evtimer_del(ev);
|
||||
}
|
||||
|
||||
static const struct dect_event_ops dect_event_ops = {
|
||||
.fd_priv_size = sizeof(struct event),
|
||||
.register_fd = register_fd,
|
||||
.unregister_fd = unregister_fd,
|
||||
.timer_priv_size = sizeof(struct event),
|
||||
.start_timer = start_timer,
|
||||
.stop_timer = stop_timer
|
||||
};
|
||||
|
||||
static struct event_base *ev_base;
|
||||
static struct event sig_event;
|
||||
static bool sigint;
|
||||
|
||||
static void sig_callback(int fd, short event, void *data)
|
||||
{
|
||||
sigint = true;
|
||||
}
|
||||
|
||||
int dect_event_ops_init(struct dect_ops *ops)
|
||||
{
|
||||
|
||||
ev_base = event_init();
|
||||
if (ev_base == NULL)
|
||||
return -1;
|
||||
ops->event_ops = &dect_event_ops;
|
||||
|
||||
signal_set(&sig_event, SIGINT, sig_callback, NULL);
|
||||
signal_add(&sig_event, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dect_event_loop(void)
|
||||
{
|
||||
while (!sigint)
|
||||
event_loop(EVLOOP_ONCE);
|
||||
signal_del(&sig_event);
|
||||
}
|
||||
|
||||
void dect_event_ops_cleanup(void)
|
||||
{
|
||||
event_base_free(ev_base);
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,74 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dect/libdect.h>
|
||||
#include "common.h"
|
||||
|
||||
enum phones { PHONE1, PHONE2, PHONE3, };
|
||||
static const struct dect_ipui ipuis[] = {
|
||||
[PHONE1] = {
|
||||
.put = DECT_IPUI_N,
|
||||
.pun.n.ipei = {
|
||||
.emc = 0x08ae,
|
||||
.psn = 0x83d1e,
|
||||
},
|
||||
},
|
||||
[PHONE2] = {
|
||||
.put = DECT_IPUI_N,
|
||||
.pun.n.ipei = {
|
||||
.emc = 0x08ae,
|
||||
.psn = 0x8969f,
|
||||
},
|
||||
},
|
||||
[PHONE3] = {
|
||||
.put = DECT_IPUI_N,
|
||||
.pun.n.ipei = {
|
||||
.emc = 0x08ae,
|
||||
.psn = 0x5b9a0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dect_mm_ops mm_ops = {
|
||||
.mm_access_rights_ind = 0,
|
||||
.mm_access_rights_cfm = 0,
|
||||
};
|
||||
|
||||
static int mm_access_rights_request(struct dect_handle *dh)
|
||||
{
|
||||
struct dect_ie_portable_identity portable_identity;
|
||||
struct dect_mm_access_rights_param param = {
|
||||
.portable_identity = &portable_identity,
|
||||
};
|
||||
|
||||
dect_ie_init(&portable_identity);
|
||||
portable_identity.type = ID_TYPE_IPUI;
|
||||
portable_identity.ipui = ipuis[PHONE1];
|
||||
|
||||
return dect_mm_access_rights_req(dh, ¶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;
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <event.h>
|
||||
|
||||
#include <dect/libdect.h>
|
||||
#include <dect/terminal.h>
|
||||
#include <dect/keypad.h>
|
||||
#include "common.h"
|
||||
|
||||
struct call {
|
||||
struct dect_keypad_buffer *keybuf;
|
||||
struct dect_audio_handle *audio;
|
||||
struct event event;
|
||||
enum {
|
||||
BLINK0,
|
||||
RING,
|
||||
BLINK1,
|
||||
SCROLLING,
|
||||
} state;
|
||||
uint8_t scroll_off;
|
||||
uint8_t ring_pattern;
|
||||
};
|
||||
|
||||
enum phones { PHONE1, PHONE2, PHONE3, };
|
||||
static const struct dect_ipui ipuis[] = {
|
||||
[PHONE1] = {
|
||||
.put = DECT_IPUI_N,
|
||||
.pun.n.ipei = {
|
||||
.emc = 0x08ae,
|
||||
.psn = 0x83d1e,
|
||||
},
|
||||
},
|
||||
[PHONE2] = {
|
||||
.put = DECT_IPUI_N,
|
||||
.pun.n.ipei = {
|
||||
.emc = 0x08ae,
|
||||
.psn = 0x8969f,
|
||||
},
|
||||
},
|
||||
[PHONE3] = {
|
||||
.put = DECT_IPUI_N,
|
||||
.pun.n.ipei = {
|
||||
.emc = 0x08ae,
|
||||
.psn = 0x5b9a0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static void dect_mncc_timer(int fd, short even, void *data);
|
||||
static void dect_mncc_timer_schedule(struct dect_call *call)
|
||||
{
|
||||
struct call *priv = dect_call_priv(call);
|
||||
struct timeval tv = { .tv_sec = 1 };
|
||||
|
||||
evtimer_set(&priv->event, dect_mncc_timer, call);
|
||||
evtimer_add(&priv->event, &tv);
|
||||
}
|
||||
|
||||
static void dect_mncc_timer(int fd, short even, void *data)
|
||||
{
|
||||
struct dect_call *call = data;
|
||||
struct dect_ie_display display;
|
||||
struct dect_ie_signal signal;
|
||||
struct dect_mncc_info_param info = {
|
||||
//.signal = &signal,
|
||||
.display = &display,
|
||||
};
|
||||
static int code;
|
||||
|
||||
init_list_head(&info.progress_indicator.list);
|
||||
dect_ie_init(&signal);
|
||||
signal.code = DECT_SIGNAL_ALERTING_BASE | (code % 10);
|
||||
|
||||
dect_display_init(&display);
|
||||
dect_display_append_char(&display, code++);
|
||||
|
||||
dect_mncc_info_req(dh, call, &info);
|
||||
dect_mncc_timer_schedule(call);
|
||||
}
|
||||
|
||||
static void dect_keypad_complete(struct dect_handle *dh, void *call,
|
||||
struct dect_ie_keypad *keypad)
|
||||
{
|
||||
printf("keypad complete: '%.*s'\n", keypad->len, keypad->info);
|
||||
}
|
||||
|
||||
static void dect_mncc_connect_ind(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_connect_param *param)
|
||||
{
|
||||
printf("MNCC_CONNECT-ind\n");
|
||||
}
|
||||
|
||||
static void dect_mncc_setup_ind(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_setup_param *setup)
|
||||
{
|
||||
struct call *priv = dect_call_priv(call);
|
||||
struct dect_ie_signal signal;
|
||||
struct dect_mncc_connect_param connect = {
|
||||
//.signal = &signal,
|
||||
};
|
||||
|
||||
printf("MNCC_SETUP-ind\n");
|
||||
dect_ie_init(&signal);
|
||||
signal.code = DECT_SIGNAL_DIAL_TONE_ON;
|
||||
|
||||
priv->keybuf = dect_keypad_buffer_init(dh, 3, dect_keypad_complete, call);
|
||||
priv->audio = dect_audio_open();
|
||||
|
||||
dect_mncc_connect_req(dh, call, &connect);
|
||||
}
|
||||
|
||||
static void dect_mncc_setup_ack_ind(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_setup_ack_param *param)
|
||||
{
|
||||
printf("MNCC_SETUP_ACK-ind\n");
|
||||
}
|
||||
|
||||
static void dect_mncc_info_ind(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_info_param *param)
|
||||
{
|
||||
struct call *priv = dect_call_priv(call);
|
||||
struct dect_ie_progress_indicator progress_indicator;
|
||||
struct dect_ie_signal signal;
|
||||
struct dect_mncc_info_param info = {
|
||||
.signal = &signal,
|
||||
};
|
||||
|
||||
printf("MNCC_INFO-ind\n");
|
||||
return;
|
||||
dect_keypad_append(dh, priv->keybuf, param->keypad,
|
||||
param->sending_complete);
|
||||
|
||||
dect_ie_init(&signal);
|
||||
signal.code = DECT_SIGNAL_DIAL_TONE_ON;
|
||||
|
||||
dect_ie_init(&progress_indicator);
|
||||
progress_indicator.location = DECT_LOCATION_PRIVATE_NETWORK_SERVING_LOCAL_USER;
|
||||
progress_indicator.progress = DECT_PROGRESS_INBAND_INFORMATION_NOW_AVAILABLE;
|
||||
|
||||
init_list_head(&info.progress_indicator.list);
|
||||
list_add_tail(&progress_indicator.common.list, &info.progress_indicator.list);
|
||||
|
||||
dect_mncc_info_req(dh, call, &info);
|
||||
}
|
||||
|
||||
static void dect_mncc_send_call_info(struct dect_call *call)
|
||||
{
|
||||
struct call *priv = dect_call_priv(call);
|
||||
struct dect_ie_display display;
|
||||
struct dect_ie_signal signal;
|
||||
struct dect_mncc_info_param info = {
|
||||
.display = &display,
|
||||
.signal = &signal,
|
||||
};
|
||||
static const char *text = " kaber ";
|
||||
|
||||
dect_display_init(&display);
|
||||
dect_display_append_char(&display, DECT_C_CLEAR_DISPLAY);
|
||||
dect_display_append_char(&display, '*');
|
||||
dect_display_append(&display, text + priv->scroll_off,
|
||||
strlen(text) - priv->scroll_off);
|
||||
dect_display_append(&display, text, priv->scroll_off);
|
||||
dect_display_append_char(&display, '*');
|
||||
|
||||
dect_ie_init(&signal);
|
||||
if (priv->state == RING) {
|
||||
signal.code = DECT_SIGNAL_ALERTING_BASE | priv->ring_pattern;
|
||||
priv->ring_pattern = (priv->ring_pattern + 1) % 8;
|
||||
} else
|
||||
signal.code = DECT_SIGNAL_ALERTING_BASE | DECT_RING_OFF;
|
||||
|
||||
if (priv->state != SCROLLING)
|
||||
priv->state++;
|
||||
else {
|
||||
priv->scroll_off = (priv->scroll_off + 1) % (strlen(text) + 1);
|
||||
if (priv->scroll_off == 0)
|
||||
priv->state = 0;
|
||||
}
|
||||
|
||||
dect_mncc_info_req(dh, call, &info);
|
||||
}
|
||||
|
||||
static void dect_mncc_info_timer(int fd, short even, void *data);
|
||||
static void dect_mncc_info_timer_schedule(struct dect_call *call)
|
||||
{
|
||||
struct call *priv = dect_call_priv(call);
|
||||
struct timeval tv = { .tv_usec = 500000 };
|
||||
|
||||
evtimer_set(&priv->event, dect_mncc_info_timer, call);
|
||||
evtimer_add(&priv->event, &tv);
|
||||
}
|
||||
|
||||
static void dect_mncc_info_timer(int fd, short even, void *data)
|
||||
{
|
||||
struct dect_call *call = data;
|
||||
|
||||
dect_mncc_send_call_info(call);
|
||||
dect_mncc_info_timer_schedule(call);
|
||||
}
|
||||
|
||||
static void dect_mncc_alert_ind(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_alert_param *param)
|
||||
{
|
||||
printf("MNCC_ALERT-ind\n");
|
||||
dect_mncc_info_timer(0, 0, call);
|
||||
}
|
||||
|
||||
static void dect_mncc_reject_ind(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_release_param *param)
|
||||
{
|
||||
struct call *priv = dect_call_priv(call);
|
||||
|
||||
printf("MNCC_REJECT-ind\n");
|
||||
event_del(&priv->event);
|
||||
}
|
||||
|
||||
static void dect_open_call(struct dect_handle *dh, const struct dect_ipui *ipui)
|
||||
{
|
||||
struct dect_ie_basic_service basic_service;
|
||||
struct dect_mncc_setup_param param = {
|
||||
.basic_service = &basic_service,
|
||||
};
|
||||
struct dect_call *call;
|
||||
struct call *priv;
|
||||
|
||||
call = dect_call_alloc(dh);
|
||||
if (call == NULL)
|
||||
return;
|
||||
priv = dect_call_priv(call);
|
||||
|
||||
dect_ie_init(&basic_service);
|
||||
basic_service.class = DECT_CALL_CLASS_NORMAL;
|
||||
basic_service.service = DECT_SERVICE_BASIC_SPEECH_DEFAULT;
|
||||
|
||||
dect_mncc_setup_req(dh, call, ipui, ¶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;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
install:
|
||||
install -d $(DESTDIR)/usr/include/dect
|
||||
install -m 644 -t $(DESTDIR)/usr/include/dect/ include/dect/*
|
|
@ -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 */
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* DECT Call Control
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _DECT_CC_H
|
||||
#define _DECT_CC_H
|
||||
|
||||
/**
|
||||
* Call Control message types
|
||||
*/
|
||||
enum dect_cc_msg_types {
|
||||
CC_RESERVED = 0x0,
|
||||
CC_ALERTING = 0x1,
|
||||
CC_CALL_PROC = 0x2,
|
||||
CC_SETUP = 0x5,
|
||||
CC_CONNECT = 0x7,
|
||||
CC_SETUP_ACK = 0xd,
|
||||
CC_CONNECT_ACK = 0xf,
|
||||
CC_SERVICE_CHANGE = 0x20,
|
||||
CC_SERVICE_ACCEPT = 0x21,
|
||||
CC_SERVICE_REJECT = 0x22,
|
||||
CC_RELEASE = 0x4d,
|
||||
CC_RELEASE_COM = 0x5a,
|
||||
CC_IWU_INFO = 0x60,
|
||||
CC_NOTIFY = 0x6e,
|
||||
CC_INFO = 0x7b,
|
||||
};
|
||||
|
||||
struct dect_cc_setup_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_fixed_identity *fixed_identity;
|
||||
struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
|
||||
struct dect_ie_basic_service *basic_service;
|
||||
struct dect_ie_repeat_indicator iwu_attributes;
|
||||
struct dect_ie_repeat_indicator call_attributes;
|
||||
struct dect_ie_repeat_indicator connection_attributes;
|
||||
struct dect_ie_cipher_info *cipher_info;
|
||||
struct dect_ie_connection_identity *connection_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_ext_ho_indicator *ext_ho_indicator;
|
||||
struct dect_ie_terminal_capability *terminal_capability;
|
||||
struct dect_ie_end_to_end_compatibility *end_to_end_compatibility;
|
||||
struct dect_ie_rate_parameters *rate_parameters;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_calling_party_number *calling_party_number;
|
||||
struct dect_ie_called_party_number *called_party_number;
|
||||
struct dect_ie_called_party_subaddress *called_party_subaddress;
|
||||
struct dect_ie_sending_complete *sending_complete;
|
||||
struct dect_ie_repeat_indicator segmented_info;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_calling_party_name *calling_party_name;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_call_information *call_information;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_info_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_location_area *location_area;
|
||||
struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_ext_ho_indicator *ext_ho_indicator;
|
||||
struct dect_ie_calling_party_number *calling_party_number;
|
||||
struct dect_ie_called_party_number *called_party_number;
|
||||
struct dect_ie_called_party_subaddress *called_party_subaddress;
|
||||
struct dect_ie_sending_complete *sending_complete;
|
||||
struct dect_ie_test_hook_control *test_hook_control;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_calling_party_name *calling_party_name;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_call_information *call_information;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_setup_ack_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_info_type *info_type;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_fixed_identity *fixed_identity;
|
||||
struct dect_ie_location_area *location_area;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_call_attributes *call_attributes;
|
||||
struct dect_ie_connection_attributes *connection_attributes;
|
||||
struct dect_ie_connection_identity *connection_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_ext_ho_indicator *ext_ho_indicator;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_delimiter_request *delimiter_request;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_call_proc_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_call_attributes *call_attributes;
|
||||
struct dect_ie_connection_attributes *connection_attributes;
|
||||
struct dect_ie_connection_identity *connection_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_alerting_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_call_attributes *call_attributes;
|
||||
struct dect_ie_connection_attributes *connection_attributes;
|
||||
struct dect_ie_connection_identity *connection_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_terminal_capability *terminal_capability;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_connect_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_call_attributes *call_attributes;
|
||||
struct dect_ie_connection_attributes *connection_attributes;
|
||||
struct dect_ie_connection_identity *connection_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_ext_ho_indicator *ext_ho_indicator;
|
||||
struct dect_ie_terminal_capability *terminal_capability;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_repeat_indicator segmented_info;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_connect_ack_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_release_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_release_reason *release_reason;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_repeat_indicator segmented_info;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_release_com_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_release_reason *release_reason;
|
||||
struct dect_ie_identity_type *identity_type;
|
||||
struct dect_ie_location_area *location_area;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_connection_attributes *connection_attributes;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_repeat_indicator segmented_info;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_service_change_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_service_change_info *service_change_info;
|
||||
struct dect_ie_call_attributes *call_attributes;
|
||||
struct dect_ie_repeat_indicator connection_attributes;
|
||||
struct dect_ie_connection_identity *connection_identity;
|
||||
struct dect_ie_repeat_indicator segmented_info;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_service_accept_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_connection_identity *connection_identity;
|
||||
struct dect_ie_repeat_indicator segmented_info;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_service_reject_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_release_reason *release_reason;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_connection_attributes *connection_attributes;
|
||||
struct dect_ie_repeat_indicator segmented_info;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_notify_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_timer_restart *timer_restart;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_cc_iwu_info_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_mms_generic_header *mms_generic_header;
|
||||
struct dect_ie_mms_object_header *mms_object_header;
|
||||
struct dect_ie_repeat_indicator mms_extended_header;
|
||||
struct dect_ie_repeat_indicator time_date;
|
||||
struct dect_ie_repeat_indicator calling_party_number;
|
||||
struct dect_ie_repeat_indicator called_party_number;
|
||||
struct dect_ie_called_party_subaddress *called_party_subaddress;
|
||||
struct dect_ie_segmented_info *segmented_info;
|
||||
struct dect_ie_alphanumeric *alphanumeric;
|
||||
struct dect_ie_repeat_indicator segmented_info2;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_segmented_info *segmented_info3;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dect_cc_states - CC call states
|
||||
*
|
||||
* @DECT_CC_NULL: T-00/F-00
|
||||
* @DECT_CC_CALL_INITIATED: T-01/F-01
|
||||
* @DECT_CC_OVERLAP_SENDING: T-02/F-02
|
||||
* @DECT_CC_CALL_PROCEEDING: T-03/F-03
|
||||
* @DECT_CC_CALL_DELIVERED: T-04/F-04
|
||||
* @DECT_CC_CALL_PRESENT: T-06/F-06
|
||||
* @DECT_CC_CALL_RECEIVED: T-07/F-07
|
||||
* @DECT_CC_CONNECT_PENDING: T-08
|
||||
* @DECT_CC_ACTIVE: T-10/F-10
|
||||
* @DECT_CC_RELEASE_PENDING: T-19/F-19
|
||||
* @DECT_CC_OVERLAP_RECEIVING: T-22/F-22
|
||||
* @DECT_CC_INCOMING_CALL_PROCEEDING: T-23/F-23
|
||||
*/
|
||||
enum dect_cc_states {
|
||||
DECT_CC_NULL,
|
||||
DECT_CC_CALL_INITIATED,
|
||||
DECT_CC_OVERLAP_SENDING,
|
||||
DECT_CC_CALL_PROCEEDING,
|
||||
DECT_CC_CALL_DELIVERED,
|
||||
DECT_CC_CALL_PRESENT,
|
||||
DECT_CC_CALL_RECEIVED,
|
||||
DECT_CC_CONNECT_PENDING,
|
||||
DECT_CC_ACTIVE,
|
||||
DECT_CC_RELEASE_PENDING,
|
||||
DECT_CC_OVERLAP_RECEIVING,
|
||||
DECT_CC_INCOMING_CALL_PROCEEDING,
|
||||
__DECT_CC_STATE_MAX
|
||||
};
|
||||
#define DECT_CC_STATE_MAX (__DECT_CC_STATE_MAX - 1)
|
||||
|
||||
/**
|
||||
* @transaction: LCE link transaction
|
||||
* @state: call state
|
||||
* @setup_timer: call setup watchdog timer
|
||||
* @lu_sap: U-Plane file descriptor
|
||||
* @priv: libdect user private storage
|
||||
*/
|
||||
struct dect_call {
|
||||
struct dect_transaction transaction;
|
||||
struct dect_ie_fixed_identity *ft_id;
|
||||
struct dect_ie_portable_identity *pt_id;
|
||||
enum dect_cc_states state;
|
||||
struct dect_timer *setup_timer;
|
||||
struct dect_fd *lu_sap;
|
||||
uint8_t priv[];
|
||||
};
|
||||
|
||||
#define DECT_CC_SETUP_TIMEOUT 20 /* seconds */
|
||||
|
||||
#endif /* _DECT_CC_H */
|
|
@ -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 */
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* DECT Call-Control (CC) NWK <-> IWU interface
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _LIBDECT_DECT_CC_H
|
||||
#define _LIBDECT_DECT_CC_H
|
||||
|
||||
#include <dect/ie.h>
|
||||
|
||||
/**
|
||||
* struct dect_mncc_setup_param - MNCC_SETUP primitive parameters
|
||||
*/
|
||||
struct dect_mncc_setup_param {
|
||||
struct dect_ie_basic_service *basic_service;
|
||||
struct dect_ie_repeat_indicator iwu_attributes;
|
||||
struct dect_ie_cipher_info *cipher_info;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_terminal_capability *terminal_capability;
|
||||
struct dect_ie_end_to_end_compatibility *end_to_end_compatibility;
|
||||
struct dect_ie_rate_parameters *rate_parameters;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_called_party_number *called_party_number;
|
||||
struct dect_ie_called_party_subaddress *called_party_subaddress;
|
||||
struct dect_ie_calling_party_number *calling_party_number;
|
||||
struct dect_ie_calling_party_name *calling_party_name;
|
||||
struct dect_ie_sending_complete *sending_complete;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_mncc_setup_ack_param {
|
||||
struct dect_ie_info_type *info_type;
|
||||
struct dect_ie_location_area *location_area;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_delimiter_request *delimiter_request;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_mncc_release_param {
|
||||
struct dect_ie_release_reason *release_reason;
|
||||
struct dect_ie_identity_type *identity_type;
|
||||
struct dect_ie_location_area *location_area;
|
||||
struct dect_ie_iwu_attributes *iwu_attributes;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_mncc_call_proc_param {
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_mncc_alert_param {
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_terminal_capability *terminal_capability;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_mncc_connect_param {
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_terminal_capability *terminal_capability;
|
||||
struct dect_ie_transit_delay *transit_delay;
|
||||
struct dect_ie_window_size *window_size;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_mncc_facility_param {
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
};
|
||||
|
||||
struct dect_mncc_info_param {
|
||||
struct dect_ie_location_area *location_area;
|
||||
struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_repeat_indicator progress_indicator;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_signal *signal;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_network_parameter *network_parameter;
|
||||
struct dect_ie_called_party_number *called_party_number;
|
||||
struct dect_ie_called_party_subaddress *called_party_subaddress;
|
||||
struct dect_ie_calling_party_number *calling_party_number;
|
||||
struct dect_ie_calling_party_name *calling_party_name;
|
||||
struct dect_ie_sending_complete *sending_complete;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_mncc_modify_param {
|
||||
struct dect_ie_service_change_info *service_change_info;
|
||||
struct dect_ie_repeat_indicator iwu_attributes;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
};
|
||||
|
||||
struct dect_mncc_hold_param {
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_release_reason *release_reason;
|
||||
};
|
||||
|
||||
struct dect_mncc_iwu_info_param {
|
||||
struct dect_ie_alphanumeric *alphanumeric;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_iwu_packet *iwu_packet;
|
||||
};
|
||||
|
||||
struct dect_handle;
|
||||
struct dect_call;
|
||||
struct dect_msg_buf;
|
||||
|
||||
extern struct dect_call *dect_call_alloc(const struct dect_handle *dh);
|
||||
extern void *dect_call_priv(struct dect_call *call);
|
||||
|
||||
extern const struct dect_ipui *dect_call_portable_identity(const struct dect_call *call);
|
||||
|
||||
struct dect_cc_ops {
|
||||
size_t priv_size;
|
||||
void (*mncc_setup_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_setup_param *param);
|
||||
void (*mncc_setup_ack_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_setup_ack_param *param);
|
||||
void (*mncc_reject_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_release_param *param);
|
||||
void (*mncc_call_proc_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_call_proc_param *param);
|
||||
void (*mncc_alert_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_alert_param *param);
|
||||
void (*mncc_connect_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_connect_param *param);
|
||||
void (*mncc_connect_cfm)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_connect_param *param);
|
||||
void (*mncc_release_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_release_param *param);
|
||||
void (*mncc_release_cfm)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_release_param *param);
|
||||
void (*mncc_facility_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_facility_param *param);
|
||||
void (*mncc_info_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_info_param *param);
|
||||
void (*mncc_modify_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_modify_param *param);
|
||||
void (*mncc_modify_cfm)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_modify_param *param);
|
||||
void (*mncc_hold_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
void (*mncc_hold_cfm)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
void (*mncc_retrieve_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
void (*mncc_retrieve_cfm)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
void (*mncc_iwu_info_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_iwu_info_param *param);
|
||||
|
||||
void (*dl_u_data_ind)(struct dect_handle *dh, struct dect_call *call,
|
||||
struct dect_msg_buf *mb);
|
||||
};
|
||||
|
||||
extern int dect_mncc_setup_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_ipui *ipui,
|
||||
const struct dect_mncc_setup_param *param);
|
||||
extern int dect_mncc_setup_ack_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_setup_ack_param *param);
|
||||
extern int dect_mncc_reject_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_release_param *param);
|
||||
extern int dect_mncc_call_proc_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_call_proc_param *param);
|
||||
extern int dect_mncc_alert_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_alert_param *param);
|
||||
extern int dect_mncc_connect_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_connect_param *param);
|
||||
extern int dect_mncc_connect_res(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_connect_param *param);
|
||||
extern int dect_mncc_release_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_release_param *param);
|
||||
extern int dect_mncc_release_res(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_release_param *param);
|
||||
extern int dect_mncc_facility_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_facility_param *param);
|
||||
extern int dect_mncc_info_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_info_param *param);
|
||||
extern int dect_mncc_modify_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_modify_param *param);
|
||||
extern int dect_mncc_modify_res(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_modify_param *param);
|
||||
extern int dect_mncc_hold_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
extern int dect_mncc_hold_res(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
extern int dect_mncc_retrieve_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
extern int dect_mncc_retrieve_res(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_hold_param *param);
|
||||
extern int dect_mncc_iwu_info_req(struct dect_handle *dh, struct dect_call *call,
|
||||
const struct dect_mncc_iwu_info_param *param);
|
||||
|
||||
extern int dect_dl_u_data_req(const struct dect_handle *dh, struct dect_call *call,
|
||||
struct dect_msg_buf *mb);
|
||||
|
||||
#endif /* _LIBDECT_DECT_CC_H */
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* DECT Identities
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _LIBDECT_DECT_IDENTITIES_H
|
||||
#define _LIBDECT_DECT_IDENTITIES_H
|
||||
|
||||
/*
|
||||
* Acess Rights Identity (ARI)
|
||||
*/
|
||||
|
||||
/**
|
||||
* DECT ARI classes
|
||||
*
|
||||
* @DECT_ARC_A: Residential and private (PBX) single- and small multiple cell systems
|
||||
* @DECT_ARC_B: Private (PABXs) multiple cell
|
||||
* @DECT_ARC_C: Public single and multiple cell systems
|
||||
* @DECT_ARC_D: Public DECT access to a GSM network
|
||||
* @DECT_ARC_E: PP to PP direct communication (private)
|
||||
*/
|
||||
enum dect_ari_classes {
|
||||
DECT_ARC_A = 0x0,
|
||||
DECT_ARC_B = 0x1,
|
||||
DECT_ARC_C = 0x2,
|
||||
DECT_ARC_D = 0x3,
|
||||
DECT_ARC_E = 0x4,
|
||||
};
|
||||
|
||||
struct dect_ari {
|
||||
enum dect_ari_classes arc;
|
||||
uint32_t fpn;
|
||||
uint32_t fps;
|
||||
union {
|
||||
uint16_t emc;
|
||||
uint16_t eic;
|
||||
uint16_t poc;
|
||||
uint32_t gop;
|
||||
uint16_t fil;
|
||||
};
|
||||
};
|
||||
|
||||
enum dect_ari_lengths {
|
||||
DECT_ARC_A_LEN = 36,
|
||||
DECT_ARC_B_LEN = 31,
|
||||
DECT_ARC_C_LEN = 31,
|
||||
DECT_ARC_D_LEN = 31,
|
||||
DECT_ARC_E_LEN = 31,
|
||||
};
|
||||
|
||||
extern bool dect_ari_cmp(const struct dect_ari *a1, const struct dect_ari *a2);
|
||||
extern uint8_t dect_parse_ari(struct dect_ari *ari, uint64_t a);
|
||||
extern uint64_t dect_build_ari(const struct dect_ari *ari);
|
||||
|
||||
/**
|
||||
* struct dect_park - Portable access rights key
|
||||
*
|
||||
* @park: FP ARI
|
||||
* @pli: FP ARI prefix length
|
||||
*/
|
||||
struct dect_park {
|
||||
struct dect_ari park;
|
||||
uint8_t pli;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dect_ipei - International portable equipment ID
|
||||
*
|
||||
* @emc: Equipment Manufacturer Code
|
||||
* @psn: Portable Equipment Serial Number
|
||||
*/
|
||||
struct dect_ipei {
|
||||
uint16_t emc;
|
||||
uint32_t psn;
|
||||
};
|
||||
|
||||
/* IPUI */
|
||||
|
||||
#define DECT_IPUI_PUT_MASK 0xf0
|
||||
#define DECT_IPUI_PUT_SHIFT 4
|
||||
|
||||
/**
|
||||
* @DECT_IPUI_N: Portable user identity type N (residential/default)
|
||||
* @DECT_IPUI_O: Portable user identity type O (private)
|
||||
* @DECT_IPUI_P: Portable user identity type P (public/public access service)
|
||||
* @DECT_IPUI_Q: Portable user identity type Q (public/general)
|
||||
* @DECT_IPUI_R: Portable user identity type R (public/IMSI)
|
||||
* @DECT_IPUI_S: Portable user identity type S (PSTN/ISDN)
|
||||
* @DECT_IPUI_T: Portable user identity type T (private extended)
|
||||
* @DECT_IPUI_U: Portable user identity type U (public/general)
|
||||
*/
|
||||
enum dect_ipui_types {
|
||||
DECT_IPUI_N = 0x0 << DECT_IPUI_PUT_SHIFT,
|
||||
DECT_IPUI_O = 0x1 << DECT_IPUI_PUT_SHIFT,
|
||||
DECT_IPUI_P = 0x2 << DECT_IPUI_PUT_SHIFT,
|
||||
DECT_IPUI_Q = 0x3 << DECT_IPUI_PUT_SHIFT,
|
||||
DECT_IPUI_R = 0x4 << DECT_IPUI_PUT_SHIFT,
|
||||
DECT_IPUI_S = 0x5 << DECT_IPUI_PUT_SHIFT,
|
||||
DECT_IPUI_T = 0x6 << DECT_IPUI_PUT_SHIFT,
|
||||
DECT_IPUI_U = 0x7 << DECT_IPUI_PUT_SHIFT,
|
||||
};
|
||||
|
||||
/**
|
||||
* @put: Portable User Identity Type
|
||||
* @pun: Type specific data
|
||||
*/
|
||||
struct dect_ipui {
|
||||
enum dect_ipui_types put;
|
||||
union {
|
||||
struct {
|
||||
struct dect_ipei ipei;
|
||||
} n;
|
||||
struct {
|
||||
uint64_t number;
|
||||
} o;
|
||||
struct {
|
||||
uint16_t poc;
|
||||
uint8_t acc[10];
|
||||
} p;
|
||||
struct {
|
||||
uint8_t bacn[10];
|
||||
} q;
|
||||
struct {
|
||||
uint64_t imsi;
|
||||
} r;
|
||||
struct {
|
||||
uint64_t number;
|
||||
} s;
|
||||
struct {
|
||||
uint16_t eic;
|
||||
uint64_t number;
|
||||
} t;
|
||||
struct {
|
||||
uint8_t cacn[10];
|
||||
} u;
|
||||
} pun;
|
||||
};
|
||||
|
||||
extern bool dect_ipui_cmp(const struct dect_ipui *u1,
|
||||
const struct dect_ipui *u2);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
enum dect_tpui_types {
|
||||
DECT_TPUI_INDIVIDUAL_ASSIGNED,
|
||||
DECT_TPUI_CONNECTIONLESS_GROUP,
|
||||
DECT_TPUI_CALL_GROUP,
|
||||
DECT_TPUI_INDIVIDUAL_DEFAULT,
|
||||
DECT_TPUI_EMERGENCY,
|
||||
};
|
||||
|
||||
/**
|
||||
* @type: TPUI type
|
||||
* @tpui: type specific value (20 bits)
|
||||
*/
|
||||
struct dect_tpui {
|
||||
enum dect_tpui_types type;
|
||||
uint32_t tpui;
|
||||
};
|
||||
|
||||
extern void dect_default_individual_tpui(struct dect_tpui *tpui,
|
||||
const struct dect_ipui *ipui);
|
||||
|
||||
/* Collective broadcast identifier */
|
||||
#define DECT_TPUI_CBI 0xcfff
|
||||
|
||||
#endif /* _LIBDECT_DECT_IDENTITIES_H */
|
|
@ -0,0 +1,767 @@
|
|||
/*
|
||||
* DECT S-Format Information Elements
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _LIBDECT_DECT_IE_H
|
||||
#define _LIBDECT_DECT_IE_H
|
||||
|
||||
#include <string.h>
|
||||
#include <dect/utils.h>
|
||||
#include <list.h>
|
||||
|
||||
/**
|
||||
* struct dect_ie_common - common representation of a DECT IE
|
||||
*
|
||||
* @list: repeat indicator list node
|
||||
* @refcnt: reference count
|
||||
*/
|
||||
struct dect_ie_common {
|
||||
struct list_head list;
|
||||
unsigned int refcnt;
|
||||
};
|
||||
|
||||
#define dect_ie_container(res, ie) container_of(ie, typeof(*res), common)
|
||||
|
||||
static inline struct dect_ie_common *__dect_ie_init(struct dect_ie_common *ie)
|
||||
{
|
||||
ie->refcnt = 1;
|
||||
return ie;
|
||||
}
|
||||
|
||||
#define dect_ie_init(ie) dect_ie_container(ie, __dect_ie_init(&(ie)->common))
|
||||
|
||||
static inline struct dect_ie_common *__dect_ie_hold(struct dect_ie_common *ie)
|
||||
{
|
||||
if (ie != NULL)
|
||||
ie->refcnt++;
|
||||
return ie;
|
||||
}
|
||||
|
||||
#define dect_ie_hold(ie) dect_ie_container(ie, __dect_ie_hold(&(ie)->common))
|
||||
|
||||
/* Repeat indicator */
|
||||
|
||||
/**
|
||||
* enum dect_ie_list_types - Repeat indicator list types
|
||||
*
|
||||
* @DECT_SFMT_IE_LIST_NORMAL: Non priorized list
|
||||
* @DECT_SFMT_IE_PRIORITIZED: Priorized list
|
||||
*/
|
||||
enum dect_ie_list_types {
|
||||
DECT_SFMT_IE_LIST_NORMAL = 0x1,
|
||||
DECT_SFMT_IE_LIST_PRIORITIZED = 0x2,
|
||||
};
|
||||
|
||||
struct dect_ie_repeat_indicator {
|
||||
struct dect_ie_common common;
|
||||
enum dect_ie_list_types type;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static inline void dect_repeat_indicator_init(struct dect_ie_repeat_indicator *ie)
|
||||
{
|
||||
dect_ie_init(ie);
|
||||
init_list_head(&ie->list);
|
||||
}
|
||||
|
||||
#define dect_foreach_ie(ptr, repeat) \
|
||||
list_for_each_entry(ptr, &(repeat).list, common.list)
|
||||
|
||||
static inline void dect_ie_list_move(struct dect_ie_repeat_indicator *to,
|
||||
struct dect_ie_repeat_indicator *from)
|
||||
{
|
||||
list_splice_init(&from->list, &to->list);
|
||||
}
|
||||
|
||||
/* Sending complete */
|
||||
|
||||
struct dect_ie_sending_complete {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Delimiter request */
|
||||
|
||||
struct dect_ie_delimiter_request {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Use TPUI */
|
||||
|
||||
struct dect_ie_use_tpui {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Basic service */
|
||||
|
||||
#define DECT_BASIC_SERVICE_CALL_CLASS_MASK 0xf0
|
||||
#define DECT_BASIC_SERVICE_CALL_CLASS_SHIFT 4
|
||||
|
||||
enum dect_call_classes {
|
||||
DECT_CALL_CLASS_MESSAGE = 0x4,
|
||||
DECT_CALL_CLASS_DECT_ISDN = 0x7,
|
||||
DECT_CALL_CLASS_NORMAL = 0x8,
|
||||
DECT_CALL_CLASS_INTERNAL = 0x9,
|
||||
DECT_CALL_CLASS_EMERGENCY = 0xa,
|
||||
DECT_CALL_CLASS_SERVICE = 0xb,
|
||||
DECT_CALL_CLASS_EXTERNAL_HO = 0xc,
|
||||
DECT_CALL_CLASS_SUPPLEMENTARY_SERVICE = 0xd,
|
||||
DECT_CALL_CLASS_QA_M = 0xe,
|
||||
};
|
||||
#define DECT_CALL_CLASS_MAX 0xf
|
||||
|
||||
#define DECT_BASIC_SERVICE_SERVICE_MASK 0x0f
|
||||
|
||||
enum dect_basic_service {
|
||||
DECT_SERVICE_BASIC_SPEECH_DEFAULT = 0x0,
|
||||
DECT_SERVICE_DECT_GSM_IWP = 0x4,
|
||||
DECT_SERVICE_UMTS_IWP = 0x6,
|
||||
DECT_SERVICE_LRMS = 0x5,
|
||||
DECT_SERVICE_GSM_IWP_SMS = 0x6,
|
||||
DECT_SERVICE_WIDEBAND_SPEECH = 0x8,
|
||||
DECT_SERVICE_OTHER = 0xf,
|
||||
};
|
||||
#define DECT_SERVICE_MAX 0xf
|
||||
|
||||
struct dect_ie_basic_service {
|
||||
struct dect_ie_common common;
|
||||
enum dect_call_classes class;
|
||||
enum dect_basic_service service;
|
||||
};
|
||||
|
||||
/* Release reason */
|
||||
|
||||
enum dect_release_reasons {
|
||||
/* general values */
|
||||
DECT_RELEASE_NORMAL = 0x0,
|
||||
DECT_RELEASE_UNEXPECTED_MESSAGE = 0x1,
|
||||
DECT_RELEASE_UNKNOWN_TRANSACTION_IDENTIFIER = 0x2,
|
||||
DECT_RELEASE_MANDATORY_IE_MISSING = 0x3,
|
||||
DECT_RELEASE_INVALID_IE_CONTENTS = 0x4,
|
||||
DECT_RELEASE_INCOMPATIBLE_SERVICE = 0x5,
|
||||
DECT_RELEASE_SERVICE_NOT_IMPLEMENTED = 0x6,
|
||||
DECT_RELEASE_NEGOTIATION_NOT_SUPPORTED = 0x7,
|
||||
DECT_RELEASE_INVALID_IDENTITY = 0x8,
|
||||
DECT_RELEASE_AUTHENTICATION_FAILED = 0x9,
|
||||
DECT_RELEASE_UNKNOWN_IDENTITY = 0xa,
|
||||
DECT_RELEASE_NEGOTIATION_FAILED = 0xb,
|
||||
DECT_RELEASE_TIMER_EXPIRY = 0xd,
|
||||
DECT_RELEASE_PARTIAL_RELEASE = 0xe,
|
||||
DECT_RELEASE_UNKNOWN = 0xf,
|
||||
/* user values */
|
||||
DECT_RELEASE_USER_DETACHED = 0x10,
|
||||
DECT_RELEASE_USER_NOT_IN_RANGE = 0x11,
|
||||
DECT_RELEASE_USER_UNKNOWN = 0x12,
|
||||
DECT_RELEASE_USER_ALREADY_ACTIVE = 0x13,
|
||||
DECT_RELEASE_USER_BUSY = 0x14,
|
||||
DECT_RELEASE_USER_REJECTION = 0x15,
|
||||
DECT_RELEASE_USER_CALL_MODIFY = 0x16,
|
||||
/* external handover values */
|
||||
DECT_RELEASE_EXTERNAL_HANDOVER_NOT_SUPPORTED = 0x21,
|
||||
DECT_RELEASE_NETWORK_PARAMETERS_MISSING = 0x22,
|
||||
DECT_RELEASE_EXTERNAL_HANDOVER_RELEASE = 0x23,
|
||||
/* temporary overload values */
|
||||
DECT_RELEASE_OVERLOAD = 0x31,
|
||||
DECT_RELEASE_INSUFFICIENT_RESOURCES = 0x32,
|
||||
DECT_RELEASE_INSUFFICIENT_BEARERS_AVAILABLE = 0x33,
|
||||
DECT_RELEASE_IWU_CONGESTION = 0x34,
|
||||
};
|
||||
|
||||
struct dect_ie_release_reason {
|
||||
struct dect_ie_common common;
|
||||
enum dect_release_reasons reason;
|
||||
};
|
||||
|
||||
/* Display IE (used for both Single Display and Multi Display) */
|
||||
|
||||
struct dect_ie_display {
|
||||
struct dect_ie_common common;
|
||||
uint8_t len;
|
||||
uint8_t info[256];
|
||||
};
|
||||
|
||||
static inline void dect_display_init(struct dect_ie_display *display)
|
||||
{
|
||||
dect_ie_init(display);
|
||||
display->len = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dect_display_append_char(struct dect_ie_display *display, char c)
|
||||
{
|
||||
display->info[display->len] = c;
|
||||
display->len++;
|
||||
}
|
||||
|
||||
static inline void dect_display_append(struct dect_ie_display *display,
|
||||
const char *str, size_t len)
|
||||
{
|
||||
memcpy(display->info + display->len, str, len);
|
||||
display->len += len;
|
||||
}
|
||||
|
||||
/* Keypad IE (used for both Single Keypad and Multi Keypad) */
|
||||
|
||||
struct dect_ie_keypad {
|
||||
struct dect_ie_common common;
|
||||
uint16_t len;
|
||||
uint8_t info[256];
|
||||
};
|
||||
|
||||
/* Signal IE */
|
||||
|
||||
// FIXME: rename to alerting
|
||||
enum dect_ring_patterns {
|
||||
DECT_RING_PATTERN_0 = 0x0,
|
||||
DECT_RING_PATTERN_1 = 0x1,
|
||||
DECT_RING_PATTERN_2 = 0x2,
|
||||
DECT_RING_PATTERN_3 = 0x3,
|
||||
DECT_RING_PATTERN_4 = 0x4,
|
||||
DECT_RING_PATTERN_5 = 0x5,
|
||||
DECT_RING_PATTERN_6 = 0x6,
|
||||
DECT_RING_PATTERN_7 = 0x7,
|
||||
DECT_RING_CONTINUOUS = 0x8,
|
||||
DECT_RING_INCOMING_CALL_RELEASED = 0xa,
|
||||
DECT_RING_INCOMING_CALL_ANSWERED = 0xb,
|
||||
DECT_RING_OFF = 0xf,
|
||||
__DECT_RING_MAX
|
||||
};
|
||||
#define DECT_RING_MAX (__DECT_RING_MAX - 1)
|
||||
|
||||
enum dect_signal_codes {
|
||||
DECT_SIGNAL_DIAL_TONE_ON = 0x0,
|
||||
DECT_SIGNAL_RING_BACK_TONE_ON = 0x1,
|
||||
DECT_SIGNAL_INTERCEPT_TONE_ON = 0x2,
|
||||
DECT_SIGNAL_NETWORK_CONGESTION_TONE_ON = 0x3,
|
||||
DECT_SIGNAL_BUSY_TONE_ON = 0x4,
|
||||
DECT_SIGNAL_CONFIRM_TONE_ON = 0x5,
|
||||
DECT_SIGNAL_ANSWER_TONE_ON = 0x6,
|
||||
DECT_SIGNAL_CALL_WAITING_TONE_ON = 0x7,
|
||||
DECT_SIGNAL_OFF_HOOK_WARNING_TONE_ON = 0x8,
|
||||
DECT_SIGNAL_NEGATIVE_ACKNOWLEDGEMENT_TONE = 0x9,
|
||||
DECT_SIGNAL_TONES_OFF = 0xf,
|
||||
DECT_SIGNAL_ALERTING_BASE = 0x40,
|
||||
};
|
||||
|
||||
struct dect_ie_signal {
|
||||
struct dect_ie_common common;
|
||||
enum dect_signal_codes code;
|
||||
};
|
||||
|
||||
static inline struct dect_ie_signal *
|
||||
dect_signal_init(struct dect_ie_signal *signal, enum dect_signal_codes code)
|
||||
{
|
||||
dect_ie_init(signal);
|
||||
signal->code = code;
|
||||
return signal;
|
||||
}
|
||||
|
||||
/* Timer restart IE */
|
||||
|
||||
enum dect_timer_restart_codes {
|
||||
DECT_TIMER_RESTART = 0x0,
|
||||
DECT_TIMER_STOP = 0x1,
|
||||
};
|
||||
|
||||
struct dect_ie_timer_restart {
|
||||
struct dect_ie_common common;
|
||||
enum dect_timer_restart_codes code;
|
||||
};
|
||||
|
||||
/* Test hook control */
|
||||
|
||||
enum dect_test_hook_ctrls {
|
||||
DECT_TEST_HOOK_ON_HOOK = 0x0,
|
||||
DECT_TEST_HOOK_OFF_HOOK = 0x1,
|
||||
};
|
||||
|
||||
struct dect_ie_test_hook_control {
|
||||
struct dect_ie_common common;
|
||||
enum dect_test_hook_ctrls hook;
|
||||
};
|
||||
|
||||
/* Allocation type IE */
|
||||
|
||||
struct dect_ie_allocation_type {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Alphanumeric IE */
|
||||
|
||||
struct dect_ie_alphanumeric {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Auth type IE */
|
||||
|
||||
enum dect_ie_auth_type_identifiers {
|
||||
AUTH_DSAA = 0x1,
|
||||
AUTH_GSM = 0x40,
|
||||
AUTH_UMTS = 0x20,
|
||||
AUTH_PROPRIETARY = 0x7f,
|
||||
};
|
||||
|
||||
enum dect_ie_auth_key_types {
|
||||
KEY_USER_AUTHENTICATION_KEY = 0x1,
|
||||
KEY_USER_PERSONAL_IDENTITY = 0x3,
|
||||
KEY_AUTHENTICATION_CODE = 0x4,
|
||||
};
|
||||
|
||||
struct dect_ie_auth_type {
|
||||
struct dect_ie_common common;
|
||||
uint8_t auth_id;
|
||||
uint8_t proprietary_auth_id;
|
||||
uint8_t auth_key_type;
|
||||
uint8_t auth_key_num;
|
||||
uint8_t flags;
|
||||
uint8_t cipher_key_num;
|
||||
};
|
||||
|
||||
/* Call attributes IE */
|
||||
|
||||
struct dect_ie_call_attributes {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Call identity IE */
|
||||
|
||||
struct dect_ie_call_identity {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Called party number IE */
|
||||
|
||||
enum number_type {
|
||||
NUMBER_TYPE_UNKNOWN = 0x0,
|
||||
NUMBER_TYPE_INTERNATIONAL = 0x1,
|
||||
NUMBER_TYPE_NATIONAL = 0x2,
|
||||
NUMBER_TYPE_NETWORK_SPECIFIC = 0x3,
|
||||
NUMBER_TYPE_SUBSCRIBER = 0x4,
|
||||
NUMBER_TYPE_ABBREVIATED = 0x6,
|
||||
NUMBER_TYPE_RESERVED = 0x7,
|
||||
};
|
||||
|
||||
enum numbering_plan_identification {
|
||||
NPI_UNKNOWN = 0x0,
|
||||
NPI_ISDN_E164 = 0x1,
|
||||
NPI_DATA_PLAN_X121 = 0x3,
|
||||
NPI_TCP_IP = 0x7,
|
||||
NPI_NATIONAL_STANDARD = 0x8,
|
||||
NPI_PRIVATE = 0x9,
|
||||
NPI_SIP = 0xa,
|
||||
NPI_INTERNET_CHARACTER_FORMAT = 0xb,
|
||||
NPI_LAN_MAC_ADDRESS = 0xc,
|
||||
NPI_X400 = 0xd,
|
||||
NPI_PROFILE_SPECIFIC = 0xe,
|
||||
NPI_RESERVED = 0xf,
|
||||
};
|
||||
|
||||
struct dect_ie_called_party_number {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Called party subaddress IE */
|
||||
|
||||
struct dect_ie_called_party_subaddress {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Calling party number IE */
|
||||
|
||||
struct dect_ie_calling_party_number {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Cipher info IE */
|
||||
|
||||
struct dect_ie_cipher_info {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Connection attributes IE */
|
||||
|
||||
struct dect_ie_connection_attributes {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Connection identity IE */
|
||||
|
||||
struct dect_ie_connection_identity {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Duration IE */
|
||||
|
||||
struct dect_ie_duration {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* End-to-end compatibility IE */
|
||||
|
||||
struct dect_ie_end_to_end_compatibility {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Facility IE */
|
||||
|
||||
struct dect_ie_facility {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Feature activate IE */
|
||||
|
||||
struct dect_ie_feature_activate {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Feature indicate IE */
|
||||
|
||||
struct dect_ie_feature_indicate {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Fixed identity IE */
|
||||
|
||||
/**
|
||||
* @ID_TYPE_ARI: Access rights identity
|
||||
* @ID_TYPE_ARI_RPN: Access rights identity plus radio fixed part number
|
||||
* @ID_TYPE_ARI_WRS: Access rights identity plus radio fixed part number for WRS
|
||||
* @ID_TYPE_PARK: Portable access rights key
|
||||
*/
|
||||
enum fixed_identity_types {
|
||||
ID_TYPE_ARI = 0x00,
|
||||
ID_TYPE_ARI_RPN = 0x01,
|
||||
ID_TYPE_ARI_WRS = 0x02,
|
||||
ID_TYPE_PARK = 0x20,
|
||||
};
|
||||
|
||||
#define S_VL_IE_FIXED_IDENTITY_MIN_SIZE 2
|
||||
|
||||
#define S_VL_IE_FIXED_IDENTITY_TYPE_MASK 0x7f
|
||||
#define S_VL_IE_FIXED_IDENTITY_LENGTH_MASK 0x7f
|
||||
|
||||
struct dect_ie_fixed_identity {
|
||||
struct dect_ie_common common;
|
||||
enum fixed_identity_types type;
|
||||
struct dect_ari ari;
|
||||
uint8_t rpn;
|
||||
};
|
||||
|
||||
/* Identity type IE */
|
||||
|
||||
struct dect_ie_identity_type {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Info type IE */
|
||||
|
||||
struct dect_ie_info_type {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* InterWorking Unit (IWU) attributes IE */
|
||||
|
||||
struct dect_ie_iwu_attributes {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* IWU packet IE */
|
||||
|
||||
struct dect_ie_iwu_packet {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* IWU to IWU IE */
|
||||
|
||||
struct dect_ie_iwu_to_iwu {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Key IE */
|
||||
|
||||
struct dect_ie_key {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Location area IE */
|
||||
|
||||
struct dect_ie_location_area {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* NetWorK (NWK) assigned identity IE */
|
||||
|
||||
struct dect_ie_nwk_assigned_identity {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Network parameter IE */
|
||||
|
||||
struct dect_ie_network_parameter {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Portable identity IE */
|
||||
|
||||
/**
|
||||
* @ID_TYPE_IPUI: International Portable User Identity (IPUI)
|
||||
* @ID_TYPE_IPEI: International Portable Equipment Identity (IPEI)
|
||||
* @ID_TYPE_TPUI: Temporary Portable User Identity (TPUI)
|
||||
*/
|
||||
enum portable_identity_types {
|
||||
ID_TYPE_IPUI = 0x0,
|
||||
ID_TYPE_IPEI = 0x10,
|
||||
ID_TYPE_TPUI = 0x20,
|
||||
};
|
||||
|
||||
struct dect_ie_portable_identity {
|
||||
struct dect_ie_common common;
|
||||
enum portable_identity_types type;
|
||||
union {
|
||||
struct dect_ipui ipui;
|
||||
};
|
||||
};
|
||||
|
||||
/* Progress indicator IE */
|
||||
|
||||
enum dect_location {
|
||||
DECT_LOCATION_USER = 0x0,
|
||||
DECT_LOCATION_PRIVATE_NETWORK_SERVING_LOCAL_USER = 0x1,
|
||||
DECT_LOCATION_PUBLIC_NETWORK_SERVING_LOCAL_USER = 0x2,
|
||||
DECT_LOCATION_PRIVATE_NETWORK_SERVING_REMOTE_USER = 0x4,
|
||||
DECT_LOCATION_PUBLIC_NETWORK_SERVING_REMOTE_USER = 0x5,
|
||||
DECT_LOCATION_INTERNATIONAL_NETWORK = 0x7,
|
||||
DECT_LOCATION_NETWORK_BEYONG_INTERWORKING_POINT = 0xa,
|
||||
DECT_LOCATION_NOT_APPLICABLE = 0xf,
|
||||
};
|
||||
|
||||
enum dect_progress_description {
|
||||
DECT_PROGRESS_NOT_END_TO_END_ISDN = 0x0,
|
||||
DECT_PROGRESS_DESTINATION_ADDRESS_NON_ISDN = 0x2,
|
||||
DECT_PROGRESS_ORIGINATION_ADDRESS_NON_ISDN = 0x3,
|
||||
DECT_PROGRESS_CALL_RETURNED_TO_ISDN = 0x4,
|
||||
DECT_PROGRESS_SERVICE_CHANGE = 0x5,
|
||||
DECT_PROGRESS_INBAND_INFORMATION_NOW_AVAILABLE = 0x8,
|
||||
DECT_PROGRESS_INBAND_INFORMATION_NOT_AVAILABLE = 0x9,
|
||||
DECT_PROGRESS_END_TO_END_ISDN = 0x40,
|
||||
};
|
||||
|
||||
struct dect_ie_progress_indicator {
|
||||
struct dect_ie_common common;
|
||||
enum dect_location location;
|
||||
enum dect_progress_description progress;
|
||||
};
|
||||
|
||||
/* RAND IE */
|
||||
|
||||
struct dect_ie_rand {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Rate parameters IE */
|
||||
|
||||
struct dect_ie_rate_parameters {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Reject reason IE */
|
||||
|
||||
enum dect_reject_reasons {
|
||||
DECT_REJECT_TPUI_UNKNOWN = 0x1,
|
||||
DECT_REJECT_IPUI_UNKNOWN = 0x2,
|
||||
DECT_REJECT_NETWORK_ASSIGNED_IDENTITY_UNKNOWN = 0x3,
|
||||
DECT_REJECT_IPEI_NOT_ACCEPTED = 0x5,
|
||||
DECT_REJECT_IPUI_NOT_ACCEPTED = 0x6,
|
||||
DECT_REJECT_AUTHENTICATION_FAILED = 0x10,
|
||||
DECT_REJECT_NO_AUTHENTICATION_ALGORITHM = 0x11,
|
||||
DECT_REJECT_AUTHENTICATION_ALGORITHM_NOT_SUPPORTED = 0x12,
|
||||
DECT_REJECT_AUTHENTICATION_KEY_NOT_SUPPORTED = 0x13,
|
||||
DECT_REJECT_UPI_NOT_ENTERED = 0x14,
|
||||
DECT_REJECT_NO_CIPHER_ALGORITHM = 0x17,
|
||||
DECT_REJECT_CIPHER_ALGORITHM_NOT_SUPPORTED = 0x18,
|
||||
DECT_REJECT_CIPHER_KEY_NOT_SUPPORTED = 0x19,
|
||||
DECT_REJECT_INCOMPATIBLE_SERVICE = 0x20,
|
||||
DECT_REJECT_FALSE_LCE_REPLY = 0x21,
|
||||
DECT_REJECT_LATE_LCE_REPLY = 0x22,
|
||||
DECT_REJECT_INVALID_TPUI = 0x23,
|
||||
DECT_REJECT_TPUI_ASSIGNMENT_LIMITS_UNACCEPTABLE = 0x24,
|
||||
DECT_REJECT_INSUFFICIENT_MEMORY = 0x2f,
|
||||
DECT_REJECT_OVERLOAD = 0x30,
|
||||
DECT_REJECT_TEST_CALL_BACK_NORMAL_EN_BLOC = 0x40,
|
||||
DECT_REJECT_TEST_CALL_BACK_NORMAL_PIECEWISE = 0x41,
|
||||
DECT_REJECT_TEST_CALL_BACK_EMERGENCY_EN_BLOC = 0x42,
|
||||
DECT_REJECT_TEST_CALL_BACK_EMERGENCY_PIECEWISE = 0x43,
|
||||
DECT_REJECT_INVALID_MESSAGE = 0x5f,
|
||||
DECT_REJECT_INFORMATION_ELEMENT_ERROR = 0x60,
|
||||
DECT_REJECT_INVALID_INFORMATION_ELEMENT_CONTENTS = 0x64,
|
||||
DECT_REJECT_TIMER_EXPIRY = 0x70,
|
||||
DECT_REJECT_PLMN_NOT_ALLOWED = 0x76,
|
||||
DECT_REJECT_LOCATION_AREA_NOT_ALLOWED = 0x80,
|
||||
DECT_REJECT_LOCATION_NATIONAL_ROAMING_NOT_ALLOWED = 0x81,
|
||||
};
|
||||
|
||||
struct dect_ie_reject_reason {
|
||||
struct dect_ie_common common;
|
||||
enum dect_reject_reasons reason;
|
||||
};
|
||||
|
||||
/* RES IE */
|
||||
|
||||
struct dect_ie_res {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* RS IE */
|
||||
|
||||
struct dect_ie_rs {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Segmented info IE */
|
||||
|
||||
struct dect_ie_segmented_info {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Service change info IE */
|
||||
|
||||
struct dect_ie_service_change_info {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Service class IE */
|
||||
|
||||
struct dect_ie_service_class {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Setup capability IE */
|
||||
|
||||
struct dect_ie_setup_capability {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Terminal capability IE */
|
||||
|
||||
struct dect_ie_terminal_capability {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Transit delay IE */
|
||||
|
||||
struct dect_ie_transit_delay {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Window size IE */
|
||||
|
||||
struct dect_ie_window_size {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* ZAP field IE */
|
||||
|
||||
struct dect_ie_zap_field {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Escape to proprietary IE */
|
||||
|
||||
struct dect_ie_escape_to_proprietary {
|
||||
struct dect_ie_common common;
|
||||
uint16_t emc;
|
||||
uint8_t content[];
|
||||
};
|
||||
|
||||
/* Model identifier IE */
|
||||
|
||||
struct dect_ie_model_identifier {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* MMS Generic Header IE */
|
||||
|
||||
struct dect_ie_mms_generic_header {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* MMS Object Header IE */
|
||||
|
||||
struct dect_ie_mms_object_header {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* MMS Extended Header IE */
|
||||
|
||||
struct dect_ie_mms_extended_header {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Time-Date IE */
|
||||
|
||||
struct dect_ie_time_date {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Ext h/o indicator IE */
|
||||
|
||||
struct dect_ie_ext_ho_indicator {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Authentication Reject Parameter IE */
|
||||
|
||||
struct dect_ie_auth_reject_parameter {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Calling party Name IE */
|
||||
|
||||
struct dect_ie_calling_party_name {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Codec List IE */
|
||||
|
||||
struct dect_ie_codec_list {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Events notification IE */
|
||||
|
||||
enum dect_event_types {
|
||||
DECT_EVENT_MESSAGE_WAITING = 0x0,
|
||||
DECT_EVENT_MISSED_CALL = 0x1,
|
||||
DECT_EVENT_WEB_CONTENT = 0x2,
|
||||
DECT_EVENT_LIST_CHANGE_INDICATION = 0x3,
|
||||
};
|
||||
|
||||
enum dect_event_message_waiting_subtypes {
|
||||
DECT_EVENT_MESSAGE_WAITING_UNKNOWN = 0x0,
|
||||
DECT_EVENT_MESSAGE_WAITING_VOICE = 0x1,
|
||||
DECT_EVENT_MESSAGE_WAITING_SMS = 0x2,
|
||||
DECT_EVENT_MESSAGE_WAITING_EMAIL = 0x3,
|
||||
};
|
||||
|
||||
enum dect_event_missed_call_subtypes {
|
||||
DECT_EVENT_MISSED_CALL_UNKNOWN = 0x0,
|
||||
DECT_EVENT_MISSED_CALL_VOICE = 0x1,
|
||||
};
|
||||
|
||||
enum dect_event_web_content_subtypes {
|
||||
DECT_EVENT_WEB_CONTENT_UNKNOWN = 0x0,
|
||||
DECT_EVENT_WEB_CONTENT_RSS = 0x1,
|
||||
};
|
||||
|
||||
struct dect_ie_events_notification {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
/* Call information IE */
|
||||
|
||||
struct dect_ie_call_information {
|
||||
struct dect_ie_common common;
|
||||
};
|
||||
|
||||
#endif /* _LIBDECT_DECT_IE_H */
|
|
@ -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 */
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* libdect main header file
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _LIBDECT_DECT_LIBDECT_H
|
||||
#define _LIBDECT_DECT_LIBDECT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <dect/identities.h>
|
||||
#include <dect/cc.h>
|
||||
#include <dect/mm.h>
|
||||
|
||||
struct dect_handle;
|
||||
|
||||
/**
|
||||
* struct dect_msg_buf - DECT message buffer
|
||||
*
|
||||
* @list: Data link TX queue node
|
||||
* @type: Message type
|
||||
* @len: Data length
|
||||
* @data: Data pointer
|
||||
* @head: Storage area for on-stack buffers
|
||||
*/
|
||||
struct dect_msg_buf {
|
||||
struct list_head list;
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint8_t *data;
|
||||
uint8_t head[128];
|
||||
};
|
||||
|
||||
extern struct dect_msg_buf *dect_mbuf_alloc(const struct dect_handle *dh);
|
||||
|
||||
static inline void dect_mbuf_pull(struct dect_msg_buf *mb, unsigned int len)
|
||||
{
|
||||
assert(len <= mb->len);
|
||||
mb->data += len;
|
||||
mb->len -= len;
|
||||
}
|
||||
|
||||
static inline void dect_mbuf_push(struct dect_msg_buf *mb, unsigned int len)
|
||||
{
|
||||
mb->data -= len;
|
||||
mb->len += len;
|
||||
assert(mb->data >= mb->head);
|
||||
}
|
||||
|
||||
static inline void dect_mbuf_reserve(struct dect_msg_buf *mb, unsigned int len)
|
||||
{
|
||||
mb->data += len;
|
||||
assert(mb->data < mb->head + sizeof(mb->head));
|
||||
}
|
||||
|
||||
/**
|
||||
* enum dect_fd_events - file descriptor events
|
||||
*
|
||||
* @DECT_FD_READ: fd readable
|
||||
* @DECT_FD_WRITE: fd writable
|
||||
*/
|
||||
enum dect_fd_events {
|
||||
DECT_FD_READ = 0x1,
|
||||
DECT_FD_WRITE = 0x2
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dect_fd - libdect file descriptor
|
||||
*
|
||||
* @callback: callback to invoke for events
|
||||
* @fd: file descriptor numer
|
||||
* @data: libdect internal data
|
||||
* @priv: libdect user private file-descriptor storage
|
||||
*/
|
||||
struct dect_fd {
|
||||
void (*callback)(struct dect_handle *,
|
||||
struct dect_fd *, uint32_t);
|
||||
int fd;
|
||||
void *data;
|
||||
uint8_t priv[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dect_timer - libdect timer
|
||||
*
|
||||
* @callback: callback to invoke on timer expiry
|
||||
* @data: libdect internal data
|
||||
* @priv: libdect user private timer storage
|
||||
*/
|
||||
struct dect_timer {
|
||||
void (*callback)(struct dect_handle *,
|
||||
struct dect_timer *);
|
||||
void *data;
|
||||
uint8_t priv[];
|
||||
};
|
||||
|
||||
struct timeval;
|
||||
struct dect_event_ops {
|
||||
size_t fd_priv_size;
|
||||
size_t timer_priv_size;
|
||||
|
||||
int (*register_fd)(const struct dect_handle *dh,
|
||||
struct dect_fd *dfd,
|
||||
uint32_t events);
|
||||
void (*unregister_fd)(const struct dect_handle *dh,
|
||||
struct dect_fd *dfd);
|
||||
|
||||
void (*start_timer)(const struct dect_handle *dh,
|
||||
struct dect_timer *timer,
|
||||
const struct timeval *tv);
|
||||
void (*stop_timer)(const struct dect_handle *dh,
|
||||
struct dect_timer *timer);
|
||||
};
|
||||
|
||||
struct dect_ops {
|
||||
void *(*malloc)(size_t size);
|
||||
void (*free)(void *ptr);
|
||||
|
||||
const struct dect_event_ops *event_ops;
|
||||
const struct dect_cc_ops *cc_ops;
|
||||
const struct dect_mm_ops *mm_ops;
|
||||
};
|
||||
|
||||
extern struct dect_handle *dect_alloc_handle(struct dect_ops *ops);
|
||||
extern void dect_close_handle(struct dect_handle *dh);
|
||||
|
||||
extern int dect_init(struct dect_handle *dh);
|
||||
|
||||
extern void dect_set_debug_hook(void (*fn)(const char *fmt, va_list ap));
|
||||
|
||||
#endif /* _LIBDECT_DECT_LIBDECT_H */
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* DECT Mobility Management (MM) NWK <-> IWU interface
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _LIBDECT_DECT_MM_H
|
||||
#define _LIBDECT_DECT_MM_H
|
||||
|
||||
#include <dect/ie.h>
|
||||
|
||||
struct dect_mm_access_rights_param {
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_fixed_identity *fixed_identity;
|
||||
struct dect_ie_location_area *location_area;
|
||||
struct dect_ie_auth_type *auth_type;
|
||||
struct dect_ie_cipher_info *cipher_info;
|
||||
struct dect_ie_zap_field *zap_field;
|
||||
struct dect_ie_service_class *service_class;
|
||||
struct dect_ie_model_identifier *model_identifier;
|
||||
struct dect_ie_reject_reason *reject_reason;
|
||||
struct dect_ie_duration *duration;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
};
|
||||
|
||||
struct dect_mm_ops {
|
||||
void (*mm_access_rights_ind)(struct dect_handle *dh,
|
||||
const struct dect_mm_access_rights_param *param);
|
||||
void (*mm_access_rights_cfm)(struct dect_handle *dh,
|
||||
const struct dect_mm_access_rights_param *param);
|
||||
};
|
||||
|
||||
extern int dect_mm_access_rights_req(struct dect_handle *dh,
|
||||
const struct dect_mm_access_rights_param *param);
|
||||
extern int dect_mm_access_rights_res(struct dect_handle *dh,
|
||||
const struct dect_mm_access_rights_param *param);
|
||||
|
||||
#endif /* _LIBDECT_DECT_MM_H */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* DECT Link Control Entity (LCE)
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _DECT_LCE_H
|
||||
#define _DECT_LCE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <linux/dect.h>
|
||||
#include <list.h>
|
||||
#include <s_fmt.h>
|
||||
#include <utils.h>
|
||||
|
||||
static inline void dect_mbuf_dump(const struct dect_msg_buf *mb,
|
||||
const char *prefix)
|
||||
{
|
||||
dect_hexdump(prefix, mb->data, mb->len);
|
||||
}
|
||||
|
||||
/**
|
||||
* enum dect_transaction_role - the LCE's role in a transaction
|
||||
*
|
||||
* @DECT_TRANSACTION_INITIATOR: Transaction was initiated by higher layer protocol entity
|
||||
* @DECT_TRANSACTION_RESPONDER: Transaction was initiated by network
|
||||
*/
|
||||
enum dect_transaction_role {
|
||||
DECT_TRANSACTION_INITIATOR,
|
||||
DECT_TRANSACTION_RESPONDER,
|
||||
};
|
||||
|
||||
/* Connectionless NWK layer transaction value */
|
||||
#define DECT_TV_CONNECTIONLESS 6
|
||||
|
||||
/**
|
||||
* struct dect_transaction - DECT protocol transaction
|
||||
*
|
||||
* @list: Datalink transaction list node
|
||||
* @link: Associated data link
|
||||
* @pd: Protocol discriminator
|
||||
* @role: Role (initiator/responder)
|
||||
* @tv: Transaction value
|
||||
*/
|
||||
enum dect_s_pd_values;
|
||||
struct dect_transaction {
|
||||
struct list_head list;
|
||||
struct dect_data_link *link;
|
||||
enum dect_s_pd_values pd;
|
||||
enum dect_transaction_role role;
|
||||
uint16_t tv;
|
||||
};
|
||||
|
||||
extern int dect_open_transaction(struct dect_handle *dh,
|
||||
struct dect_transaction *ta,
|
||||
const struct dect_ipui *ipui);
|
||||
extern void dect_confirm_transaction(struct dect_handle *dh,
|
||||
struct dect_transaction *ta,
|
||||
const struct dect_transaction *req);
|
||||
extern void dect_close_transaction(struct dect_handle *dh,
|
||||
struct dect_transaction *ta);
|
||||
extern void dect_transaction_get_ulei(struct sockaddr_dect_lu *addr,
|
||||
const struct dect_transaction *ta);
|
||||
|
||||
extern int dect_lce_send(const struct dect_handle *dh,
|
||||
const struct dect_transaction *ta,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
const struct dect_msg_common *msg, uint8_t type,
|
||||
const char *prefix);
|
||||
|
||||
/**
|
||||
* struct dect_nwk_protocol - NWK layer protocol
|
||||
*
|
||||
* @name: Protocol name
|
||||
* @pd: Protocol discriminator
|
||||
* @open: Open a new transaction initiated by the network
|
||||
* @shutdown: Perform an active shutdown of the transaction
|
||||
* @rcv: Receive a message related to an active transaction
|
||||
*/
|
||||
struct dect_nwk_protocol {
|
||||
const char *name;
|
||||
enum dect_s_pd_values pd;
|
||||
uint16_t max_transactions;
|
||||
void (*open)(struct dect_handle *dh,
|
||||
const struct dect_transaction *req,
|
||||
struct dect_msg_buf *mb);
|
||||
void (*shutdown)(struct dect_handle *dh,
|
||||
struct dect_transaction *req);
|
||||
void (*rcv)(struct dect_handle *dh,
|
||||
struct dect_transaction *ta,
|
||||
struct dect_msg_buf *mb);
|
||||
};
|
||||
|
||||
extern void dect_lce_register_protocol(const struct dect_nwk_protocol *protocol);
|
||||
|
||||
/**
|
||||
* struct dect_lte - Location Table Entry
|
||||
*
|
||||
* @list: Location table list node
|
||||
* @ipui: International Portable User ID
|
||||
* @tpui: Temporary Portable User ID
|
||||
*/
|
||||
struct dect_lte {
|
||||
struct list_head list;
|
||||
struct dect_ipui ipui;
|
||||
struct dect_tpui tpui;
|
||||
};
|
||||
|
||||
struct dect_location_table {
|
||||
struct list_head entries;
|
||||
};
|
||||
|
||||
enum dect_data_link_states {
|
||||
DECT_DATA_LINK_RELEASED,
|
||||
DECT_DATA_LINK_ESTABLISHED,
|
||||
DECT_DATA_LINK_ESTABLISH_PENDING,
|
||||
DECT_DATA_LINK_RELEASE_PENDING,
|
||||
DECT_DATA_LINK_SUSPENDED,
|
||||
DECT_DATA_LINK_SUSPEND_PENDING,
|
||||
DECT_DATA_LINK_RESUME_PENDING,
|
||||
__DECT_DATA_LINK_STATE_MAX
|
||||
};
|
||||
#define DECT_DATA_LINK_STATE_MAX (__DECT_DATA_LINK_STATE_MAX - 1)
|
||||
|
||||
/**
|
||||
* struct dect_data_link
|
||||
*
|
||||
* @list: DECT handle link list node
|
||||
* @dfd: Associated socket file descriptor
|
||||
* @dlei: Data Link Endpoint identifier
|
||||
* @ipui: International Portable User ID
|
||||
* @state: Data link state
|
||||
* @sdu_timer: Establish without SDU timer
|
||||
* @msg_queue: Message queue used during ESTABLISH_PENDING state
|
||||
*/
|
||||
struct dect_data_link {
|
||||
struct list_head list;
|
||||
struct sockaddr_dect_ssap dlei;
|
||||
struct dect_ipui ipui;
|
||||
struct dect_fd *dfd;
|
||||
enum dect_data_link_states state;
|
||||
struct dect_timer *sdu_timer;
|
||||
struct list_head transactions;
|
||||
struct list_head msg_queue;
|
||||
};
|
||||
|
||||
#define DECT_DDL_ESTABLISH_SDU_TIMEOUT 5 /* seconds */
|
||||
|
||||
extern int dect_lce_group_ring(struct dect_handle *dh,
|
||||
enum dect_ring_patterns pattern);
|
||||
|
||||
/* LCE message types */
|
||||
enum dect_lce_msg_types {
|
||||
DECT_LCE_PAGE_RESPONSE = 0x71,
|
||||
DECT_LCE_PAGE_REJECT = 0x72,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dect_lce_page_response - LCE Page response S-Format message
|
||||
*
|
||||
* @common: Message header
|
||||
* @portable_identity: Portable Identity IE
|
||||
* @fixed_identity: Fixed Identity IE
|
||||
* @nwk_assigned_identity: NWK-assigned Identity IE (optional)
|
||||
* @cipher_info: Cipher Info IE (optional)
|
||||
* @escape_to_proprietary: Escape to proprietary IE (optional)
|
||||
*/
|
||||
struct dect_lce_page_response {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_fixed_identity *fixed_identity;
|
||||
struct dect_ie_nwk_assigned_identity *nwk_assigned_identity;
|
||||
struct dect_ie_cipher_info *cipher_info;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dect_lce_page_reject - LCE Page reject S-Format message
|
||||
*
|
||||
* @common: Message header
|
||||
* @portable_identity: Portable Identity IE
|
||||
* @fixed_identity: Fixed Identity IE
|
||||
* @reject_reason: Reject reason IE
|
||||
* @escape_to_proprietary: Escape to proprietary IE (optional)
|
||||
*/
|
||||
struct dect_lce_page_reject {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_fixed_identity *fixed_identity;
|
||||
struct dect_ie_reject_reason *reject_reason;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
extern int dect_lce_init(struct dect_handle *dh);
|
||||
extern void dect_lce_exit(struct dect_handle *dh);
|
||||
|
||||
#endif /* _DECT_LCE_H */
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef _LIBDECT_H
|
||||
#define _LIBDECT_H
|
||||
|
||||
#include <linux/dect_netlink.h>
|
||||
#include <dect/libdect.h>
|
||||
#include <list.h>
|
||||
|
||||
/**
|
||||
* struct dect_handle - libdect handle
|
||||
*
|
||||
* @ops: user ops
|
||||
* @nlsock: netlink socket
|
||||
* @nlfd: netlink file descriptor
|
||||
* @index: cluster index
|
||||
* @mode: cluster mode
|
||||
* @pari: FP's PARI
|
||||
* @b_sap: B-SAP socket
|
||||
* @s_sap: S-SAP listener socket
|
||||
* @links: list of data links
|
||||
*/
|
||||
struct dect_handle {
|
||||
const struct dect_ops *ops;
|
||||
struct nl_sock *nlsock;
|
||||
struct dect_fd *nlfd;
|
||||
|
||||
unsigned int index;
|
||||
enum dect_cluster_modes mode;
|
||||
struct dect_ari pari;
|
||||
|
||||
struct dect_fd *b_sap;
|
||||
struct dect_fd *s_sap;
|
||||
struct list_head links;
|
||||
};
|
||||
|
||||
#endif /* _LIBDECT_H */
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef _LINUX_DECT_H
|
||||
#define _LINUX_DECT_H
|
||||
|
||||
#define DECTNAMSIZ 16
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
/* these have to be macros in order to be usable for module aliases */
|
||||
#define DECT_RAW 0 /* raw frames */
|
||||
#define DECT_B_SAP 1 /* DLC Broadcast Service */
|
||||
#define DECT_S_SAP 2 /* DLC Data Link Service */
|
||||
#define DECT_LU1_SAP 3 /* LU1 sockets */
|
||||
#define DECT_PROTO_NUM 4
|
||||
|
||||
/**
|
||||
* struct sockaddr_dect
|
||||
*
|
||||
* @dect_family: address family (AF_DECT)
|
||||
* @dect_index: cluster index
|
||||
*/
|
||||
struct sockaddr_dect {
|
||||
sa_family_t dect_family;
|
||||
int dect_index;
|
||||
};
|
||||
|
||||
/* raw sockets */
|
||||
|
||||
#define DECT_RAW_AUXDATA 0
|
||||
|
||||
/**
|
||||
* struct dect_raw_auxdata - raw socket auxiliary frame data
|
||||
*
|
||||
* @mfn: multi-frame number
|
||||
* @frame: frame number
|
||||
* @slot: slot numer
|
||||
* @rssi: receive signal strength indicator
|
||||
*/
|
||||
struct dect_raw_auxdata {
|
||||
__u32 mfn;
|
||||
__u8 frame;
|
||||
__u8 slot;
|
||||
__u8 rssi;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sockaddr_dect_ssap
|
||||
*
|
||||
* @dect_family: family (AF_DECT)
|
||||
* @dect_dlei: Data Link Endpoint Identifier
|
||||
* @dect_class: Class A/B
|
||||
*/
|
||||
struct sockaddr_dect_ssap {
|
||||
sa_family_t dect_family;
|
||||
__u64 dect_ari:40,
|
||||
dect_pmid:20,
|
||||
dect_lcn:3;
|
||||
__u8 dect_lln:4,
|
||||
dect_sapi:4;
|
||||
__u8 dect_class;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sockaddr_dect_lu - DLC U-plane LUx service instance address
|
||||
*
|
||||
* @dect_family: address family (AF_DECT)
|
||||
* @dect_mci: MAC Connection Identifier
|
||||
*/
|
||||
struct sockaddr_dect_lu {
|
||||
sa_family_t dect_family;
|
||||
__u64 dect_ari:40,
|
||||
dect_pmid:20,
|
||||
dect_lcn:3;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_DECT_H */
|
|
@ -0,0 +1,306 @@
|
|||
#ifndef _LINUX_SOCKET_H
|
||||
#define _LINUX_SOCKET_H
|
||||
|
||||
/*
|
||||
* Desired design of maximum size and alignment (see RFC2553)
|
||||
*/
|
||||
#define _K_SS_MAXSIZE 128 /* Implementation specific max size */
|
||||
#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *))
|
||||
/* Implementation specific desired alignment */
|
||||
|
||||
struct __kernel_sockaddr_storage {
|
||||
unsigned short ss_family; /* address family */
|
||||
/* Following field(s) are implementation specific */
|
||||
char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
|
||||
/* space to achieve desired size, */
|
||||
/* _SS_MAXSIZE value minus size of ss_family */
|
||||
} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
|
||||
|
||||
#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
|
||||
|
||||
#include <asm/socket.h> /* arch-dependent defines */
|
||||
#include <linux/sockios.h> /* the SIOCxxx I/O controls */
|
||||
#include <linux/uio.h> /* iovec support */
|
||||
#include <linux/types.h> /* pid_t */
|
||||
/* */
|
||||
|
||||
|
||||
typedef unsigned short sa_family_t;
|
||||
|
||||
/*
|
||||
* 1003.1g requires sa_family_t and that sa_data is char.
|
||||
*/
|
||||
|
||||
struct sockaddr {
|
||||
sa_family_t sa_family; /* address family, AF_xxx */
|
||||
char sa_data[14]; /* 14 bytes of protocol address */
|
||||
};
|
||||
|
||||
struct linger {
|
||||
int l_onoff; /* Linger active */
|
||||
int l_linger; /* How long to linger for */
|
||||
};
|
||||
|
||||
#define sockaddr_storage __kernel_sockaddr_storage
|
||||
|
||||
/*
|
||||
* As we do 4.4BSD message passing we use a 4.4BSD message passing
|
||||
* system, not 4.3. Thus msg_accrights(len) are now missing. They
|
||||
* belong in an obscure libc emulation or the bin.
|
||||
*/
|
||||
|
||||
struct msghdr {
|
||||
void * msg_name; /* Socket name */
|
||||
int msg_namelen; /* Length of name */
|
||||
struct iovec * msg_iov; /* Data blocks */
|
||||
__kernel_size_t msg_iovlen; /* Number of blocks */
|
||||
void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
|
||||
__kernel_size_t msg_controllen; /* Length of cmsg list */
|
||||
unsigned msg_flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* POSIX 1003.1g - ancillary data object information
|
||||
* Ancillary data consits of a sequence of pairs of
|
||||
* (cmsghdr, cmsg_data[])
|
||||
*/
|
||||
|
||||
struct cmsghdr {
|
||||
__kernel_size_t cmsg_len; /* data byte count, including hdr */
|
||||
int cmsg_level; /* originating protocol */
|
||||
int cmsg_type; /* protocol-specific type */
|
||||
};
|
||||
|
||||
/*
|
||||
* Ancilliary data object information MACROS
|
||||
* Table 5-14 of POSIX 1003.1g
|
||||
*/
|
||||
|
||||
#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg))
|
||||
#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
|
||||
|
||||
#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
|
||||
|
||||
#define CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
|
||||
#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
|
||||
#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
|
||||
|
||||
#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \
|
||||
(struct cmsghdr *)(ctl) : \
|
||||
(struct cmsghdr *)NULL)
|
||||
#define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
|
||||
#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
|
||||
(cmsg)->cmsg_len <= (unsigned long) \
|
||||
((mhdr)->msg_controllen - \
|
||||
((char *)(cmsg) - (char *)(mhdr)->msg_control)))
|
||||
|
||||
/*
|
||||
* This mess will go away with glibc
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define __KINLINE static __inline__
|
||||
#elif defined(__cplusplus)
|
||||
#define __KINLINE static __inline__
|
||||
#else
|
||||
#define __KINLINE static
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Get the next cmsg header
|
||||
*
|
||||
* PLEASE, do not touch this function. If you think, that it is
|
||||
* incorrect, grep kernel sources and think about consequences
|
||||
* before trying to improve it.
|
||||
*
|
||||
* Now it always returns valid, not truncated ancillary object
|
||||
* HEADER. But caller still MUST check, that cmsg->cmsg_len is
|
||||
* inside range, given by msg->msg_controllen before using
|
||||
* ancillary object DATA. --ANK (980731)
|
||||
*/
|
||||
|
||||
__KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
|
||||
struct cmsghdr *__cmsg)
|
||||
{
|
||||
struct cmsghdr * __ptr;
|
||||
|
||||
__ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len));
|
||||
if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
|
||||
return (struct cmsghdr *)0;
|
||||
|
||||
return __ptr;
|
||||
}
|
||||
|
||||
__KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
|
||||
{
|
||||
return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
|
||||
}
|
||||
|
||||
/* "Socket"-level control message types: */
|
||||
|
||||
#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
|
||||
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
|
||||
#define SCM_SECURITY 0x03 /* rw: security label */
|
||||
|
||||
struct ucred {
|
||||
__u32 pid;
|
||||
__u32 uid;
|
||||
__u32 gid;
|
||||
};
|
||||
|
||||
/* Supported address families. */
|
||||
#define AF_UNSPEC 0
|
||||
#define AF_UNIX 1 /* Unix domain sockets */
|
||||
#define AF_LOCAL 1 /* POSIX name for AF_UNIX */
|
||||
#define AF_INET 2 /* Internet IP Protocol */
|
||||
#define AF_AX25 3 /* Amateur Radio AX.25 */
|
||||
#define AF_IPX 4 /* Novell IPX */
|
||||
#define AF_APPLETALK 5 /* AppleTalk DDP */
|
||||
#define AF_NETROM 6 /* Amateur Radio NET/ROM */
|
||||
#define AF_BRIDGE 7 /* Multiprotocol bridge */
|
||||
#define AF_ATMPVC 8 /* ATM PVCs */
|
||||
#define AF_X25 9 /* Reserved for X.25 project */
|
||||
#define AF_INET6 10 /* IP version 6 */
|
||||
#define AF_ROSE 11 /* Amateur Radio X.25 PLP */
|
||||
#define AF_DECnet 12 /* Reserved for DECnet project */
|
||||
#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/
|
||||
#define AF_SECURITY 14 /* Security callback pseudo AF */
|
||||
#define AF_KEY 15 /* PF_KEY key management API */
|
||||
#define AF_NETLINK 16
|
||||
#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */
|
||||
#define AF_PACKET 17 /* Packet family */
|
||||
#define AF_ASH 18 /* Ash */
|
||||
#define AF_ECONET 19 /* Acorn Econet */
|
||||
#define AF_ATMSVC 20 /* ATM SVCs */
|
||||
#define AF_RDS 21 /* RDS sockets */
|
||||
#define AF_SNA 22 /* Linux SNA Project (nutters!) */
|
||||
#define AF_IRDA 23 /* IRDA sockets */
|
||||
#define AF_PPPOX 24 /* PPPoX sockets */
|
||||
#define AF_WANPIPE 25 /* Wanpipe API Sockets */
|
||||
#define AF_LLC 26 /* Linux LLC */
|
||||
#define AF_CAN 29 /* Controller Area Network */
|
||||
#define AF_TIPC 30 /* TIPC sockets */
|
||||
#define AF_BLUETOOTH 31 /* Bluetooth sockets */
|
||||
#define AF_IUCV 32 /* IUCV sockets */
|
||||
#define AF_RXRPC 33 /* RxRPC sockets */
|
||||
#define AF_ISDN 34 /* mISDN sockets */
|
||||
#define AF_PHONET 35 /* Phonet sockets */
|
||||
#define AF_DECT 36 /* DECT sockets */
|
||||
#define AF_MAX 37 /* For now.. */
|
||||
|
||||
/* Protocol families, same as address families. */
|
||||
#define PF_UNSPEC AF_UNSPEC
|
||||
#define PF_UNIX AF_UNIX
|
||||
#define PF_LOCAL AF_LOCAL
|
||||
#define PF_INET AF_INET
|
||||
#define PF_AX25 AF_AX25
|
||||
#define PF_IPX AF_IPX
|
||||
#define PF_APPLETALK AF_APPLETALK
|
||||
#define PF_NETROM AF_NETROM
|
||||
#define PF_BRIDGE AF_BRIDGE
|
||||
#define PF_ATMPVC AF_ATMPVC
|
||||
#define PF_X25 AF_X25
|
||||
#define PF_INET6 AF_INET6
|
||||
#define PF_ROSE AF_ROSE
|
||||
#define PF_DECnet AF_DECnet
|
||||
#define PF_NETBEUI AF_NETBEUI
|
||||
#define PF_SECURITY AF_SECURITY
|
||||
#define PF_KEY AF_KEY
|
||||
#define PF_NETLINK AF_NETLINK
|
||||
#define PF_ROUTE AF_ROUTE
|
||||
#define PF_PACKET AF_PACKET
|
||||
#define PF_ASH AF_ASH
|
||||
#define PF_ECONET AF_ECONET
|
||||
#define PF_ATMSVC AF_ATMSVC
|
||||
#define PF_RDS AF_RDS
|
||||
#define PF_SNA AF_SNA
|
||||
#define PF_IRDA AF_IRDA
|
||||
#define PF_PPPOX AF_PPPOX
|
||||
#define PF_WANPIPE AF_WANPIPE
|
||||
#define PF_LLC AF_LLC
|
||||
#define PF_CAN AF_CAN
|
||||
#define PF_TIPC AF_TIPC
|
||||
#define PF_BLUETOOTH AF_BLUETOOTH
|
||||
#define PF_IUCV AF_IUCV
|
||||
#define PF_RXRPC AF_RXRPC
|
||||
#define PF_ISDN AF_ISDN
|
||||
#define PF_PHONET AF_PHONET
|
||||
#define PF_DECT AF_DECT
|
||||
#define PF_MAX AF_MAX
|
||||
|
||||
/* Maximum queue length specifiable by listen. */
|
||||
#define SOMAXCONN 128
|
||||
|
||||
/* Flags we can use with send/ and recv.
|
||||
Added those for 1003.1g not all are supported yet
|
||||
*/
|
||||
|
||||
#define MSG_OOB 1
|
||||
#define MSG_PEEK 2
|
||||
#define MSG_DONTROUTE 4
|
||||
#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */
|
||||
#define MSG_CTRUNC 8
|
||||
#define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */
|
||||
#define MSG_TRUNC 0x20
|
||||
#define MSG_DONTWAIT 0x40 /* Nonblocking io */
|
||||
#define MSG_EOR 0x80 /* End of record */
|
||||
#define MSG_WAITALL 0x100 /* Wait for a full request */
|
||||
#define MSG_FIN 0x200
|
||||
#define MSG_SYN 0x400
|
||||
#define MSG_CONFIRM 0x800 /* Confirm path validity */
|
||||
#define MSG_RST 0x1000
|
||||
#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */
|
||||
#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */
|
||||
#define MSG_MORE 0x8000 /* Sender will send more */
|
||||
|
||||
#define MSG_EOF MSG_FIN
|
||||
|
||||
#define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exit for file
|
||||
descriptor received through
|
||||
SCM_RIGHTS */
|
||||
#if defined(CONFIG_COMPAT)
|
||||
#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
|
||||
#else
|
||||
#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */
|
||||
#endif
|
||||
|
||||
|
||||
/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */
|
||||
#define SOL_IP 0
|
||||
/* #define SOL_ICMP 1 No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */
|
||||
#define SOL_TCP 6
|
||||
#define SOL_UDP 17
|
||||
#define SOL_IPV6 41
|
||||
#define SOL_ICMPV6 58
|
||||
#define SOL_SCTP 132
|
||||
#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */
|
||||
#define SOL_RAW 255
|
||||
#define SOL_IPX 256
|
||||
#define SOL_AX25 257
|
||||
#define SOL_ATALK 258
|
||||
#define SOL_NETROM 259
|
||||
#define SOL_ROSE 260
|
||||
#define SOL_DECNET 261
|
||||
#define SOL_X25 262
|
||||
#define SOL_PACKET 263
|
||||
#define SOL_ATM 264 /* ATM layer (cell level) */
|
||||
#define SOL_AAL 265 /* ATM Adaption Layer (packet level) */
|
||||
#define SOL_IRDA 266
|
||||
#define SOL_NETBEUI 267
|
||||
#define SOL_LLC 268
|
||||
#define SOL_DCCP 269
|
||||
#define SOL_NETLINK 270
|
||||
#define SOL_TIPC 271
|
||||
#define SOL_RXRPC 272
|
||||
#define SOL_PPPOL2TP 273
|
||||
#define SOL_BLUETOOTH 274
|
||||
#define SOL_PNPIPE 275
|
||||
#define SOL_RDS 276
|
||||
#define SOL_DECT 277
|
||||
|
||||
/* IPX options */
|
||||
#define IPX_TYPE 1
|
||||
|
||||
#endif /* not kernel and not glibc */
|
||||
#endif /* _LINUX_SOCKET_H */
|
|
@ -0,0 +1,625 @@
|
|||
#ifndef _LINUX_LIST_H
|
||||
#define _LINUX_LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define prefetch(x) ((void)0)
|
||||
|
||||
#define LIST_POISON1 ((void *)0x12345678)
|
||||
#define LIST_POISON2 ((void *)0x87654321)
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
static inline void init_list_head(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty() on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
entry->next = LIST_POISON1;
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_replace - replace old entry by new one
|
||||
* @old : the element to be replaced
|
||||
* @new : the new element to insert
|
||||
*
|
||||
* If @old was empty, it will be overwritten.
|
||||
*/
|
||||
static inline void list_replace(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
new->next = old->next;
|
||||
new->next->prev = new;
|
||||
new->prev = old->prev;
|
||||
new->prev->next = new;
|
||||
}
|
||||
|
||||
static inline void list_replace_init(struct list_head *old,
|
||||
struct list_head *new)
|
||||
{
|
||||
list_replace(old, new);
|
||||
init_list_head(old);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static inline void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
init_list_head(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move - delete from one list and add as another's head
|
||||
* @list: the entry to move
|
||||
* @head: the head that will precede our entry
|
||||
*/
|
||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_move_tail - delete from one list and add as another's tail
|
||||
* @list: the entry to move
|
||||
* @head: the head that will follow our entry
|
||||
*/
|
||||
static inline void list_move_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
__list_del(list->prev, list->next);
|
||||
list_add_tail(list, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_is_last - tests whether @list is the last entry in list @head
|
||||
* @list: the entry to test
|
||||
* @head: the head of the list
|
||||
*/
|
||||
static inline int list_is_last(const struct list_head *list,
|
||||
const struct list_head *head)
|
||||
{
|
||||
return list->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty_careful - tests whether a list is empty and not being modified
|
||||
* @head: the list to test
|
||||
*
|
||||
* Description:
|
||||
* tests whether a list is empty _and_ checks that no other CPU might be
|
||||
* in the process of modifying either member (next or prev)
|
||||
*
|
||||
* NOTE: using list_empty_careful() without synchronization
|
||||
* can only be safe if the only activity that can happen
|
||||
* to the list entry is list_del_init(). Eg. it cannot be used
|
||||
* if another CPU could re-list_add() it.
|
||||
*/
|
||||
static inline int list_empty_careful(const struct list_head *head)
|
||||
{
|
||||
struct list_head *next = head->next;
|
||||
return (next == head) && (next == head->prev);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_is_singular - tests whether a list has just one entry.
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_is_singular(const struct list_head *head)
|
||||
{
|
||||
return !list_empty(head) && (head->next == head->prev);
|
||||
}
|
||||
|
||||
static inline void __list_cut_position(struct list_head *list,
|
||||
struct list_head *head, struct list_head *entry)
|
||||
{
|
||||
struct list_head *new_first = entry->next;
|
||||
list->next = head->next;
|
||||
list->next->prev = list;
|
||||
list->prev = entry;
|
||||
entry->next = list;
|
||||
head->next = new_first;
|
||||
new_first->prev = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_cut_position - cut a list into two
|
||||
* @list: a new list to add all removed entries
|
||||
* @head: a list with entries
|
||||
* @entry: an entry within head, could be the head itself
|
||||
* and if so we won't cut the list
|
||||
*
|
||||
* This helper moves the initial part of @head, up to and
|
||||
* including @entry, from @head to @list. You should
|
||||
* pass on @entry an element you know is on @head. @list
|
||||
* should be an empty list or a list you do not care about
|
||||
* losing its data.
|
||||
*
|
||||
*/
|
||||
static inline void list_cut_position(struct list_head *list,
|
||||
struct list_head *head, struct list_head *entry)
|
||||
{
|
||||
if (list_empty(head))
|
||||
return;
|
||||
if (list_is_singular(head) &&
|
||||
(head->next != entry && head != entry))
|
||||
return;
|
||||
if (entry == head)
|
||||
init_list_head(list);
|
||||
else
|
||||
__list_cut_position(list, head, entry);
|
||||
}
|
||||
|
||||
static inline void __list_splice(const struct list_head *list,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
struct list_head *last = list->prev;
|
||||
|
||||
first->prev = prev;
|
||||
prev->next = first;
|
||||
|
||||
last->next = next;
|
||||
next->prev = last;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists, this is designed for stacks
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice(const struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_tail - join two lists, each list being a queue
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static inline void list_splice_tail(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list))
|
||||
__list_splice(list, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head, head->next);
|
||||
init_list_head(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice_tail_init - join two lists and reinitialise the emptied list
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*
|
||||
* Each of the lists is a queue.
|
||||
* The list at @list is reinitialised
|
||||
*/
|
||||
static inline void list_splice_tail_init(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
if (!list_empty(list)) {
|
||||
__list_splice(list, head->prev, head);
|
||||
init_list_head(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||
prefetch(pos->member.next), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_reverse(pos, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
||||
prefetch(pos->member.prev), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
||||
* @pos: the type * to use as a start point
|
||||
* @head: the head of the list
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
||||
*/
|
||||
#define list_prepare_entry(pos, head, member) \
|
||||
((pos) ? : list_entry(head, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue - continue iteration over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Continue to iterate over list of given type, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define list_for_each_entry_continue(pos, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
prefetch(pos->member.next), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Start to iterate over list of given type backwards, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
||||
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
|
||||
prefetch(pos->member.prev), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_from - iterate over list of given type from the current point
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing from current position.
|
||||
*/
|
||||
#define list_for_each_entry_from(pos, head, member) \
|
||||
for (; prefetch(pos->member.next), &pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_continue
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate over list of given type, continuing after current point,
|
||||
* safe against removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
||||
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_from
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate over list of given type from current point, safe against
|
||||
* removal of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
||||
for (n = list_entry(pos->member.next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe_reverse
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*
|
||||
* Iterate backwards over list of given type, safe against removal
|
||||
* of list entry.
|
||||
*/
|
||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
||||
for (pos = list_entry((head)->prev, typeof(*pos), member), \
|
||||
n = list_entry(pos->member.prev, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
|
||||
|
||||
/*
|
||||
* Double linked lists with a single pointer list head.
|
||||
* Mostly useful for hash tables where the two pointer list head is
|
||||
* too wasteful.
|
||||
* You lose the ability to access the tail in O(1).
|
||||
*/
|
||||
|
||||
struct hlist_head {
|
||||
struct hlist_node *first;
|
||||
};
|
||||
|
||||
struct hlist_node {
|
||||
struct hlist_node *next, **pprev;
|
||||
};
|
||||
|
||||
#define HLIST_HEAD_INIT { .first = NULL }
|
||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
||||
|
||||
#define init_hlist_head(ptr) ((ptr)->first = NULL)
|
||||
|
||||
static inline void init_hlist_node(struct hlist_node *h)
|
||||
{
|
||||
h->next = NULL;
|
||||
h->pprev = NULL;
|
||||
}
|
||||
|
||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
||||
{
|
||||
return !h->pprev;
|
||||
}
|
||||
|
||||
static inline int hlist_empty(const struct hlist_head *h)
|
||||
{
|
||||
return !h->first;
|
||||
}
|
||||
|
||||
static inline void __hlist_del(struct hlist_node *n)
|
||||
{
|
||||
struct hlist_node *next = n->next;
|
||||
struct hlist_node **pprev = n->pprev;
|
||||
*pprev = next;
|
||||
if (next)
|
||||
next->pprev = pprev;
|
||||
}
|
||||
|
||||
static inline void hlist_del(struct hlist_node *n)
|
||||
{
|
||||
__hlist_del(n);
|
||||
n->next = LIST_POISON1;
|
||||
n->pprev = LIST_POISON2;
|
||||
}
|
||||
|
||||
static inline void hlist_del_init(struct hlist_node *n)
|
||||
{
|
||||
if (!hlist_unhashed(n)) {
|
||||
__hlist_del(n);
|
||||
init_hlist_node(n);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
||||
{
|
||||
struct hlist_node *first = h->first;
|
||||
n->next = first;
|
||||
if (first)
|
||||
first->pprev = &n->next;
|
||||
h->first = n;
|
||||
n->pprev = &h->first;
|
||||
}
|
||||
|
||||
/* next must be != NULL */
|
||||
static inline void hlist_add_before(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
n->pprev = next->pprev;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
*(n->pprev) = n;
|
||||
}
|
||||
|
||||
static inline void hlist_add_after(struct hlist_node *n,
|
||||
struct hlist_node *next)
|
||||
{
|
||||
next->next = n->next;
|
||||
n->next = next;
|
||||
next->pprev = &n->next;
|
||||
|
||||
if(next->next)
|
||||
next->next->pprev = &next->next;
|
||||
}
|
||||
|
||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
||||
|
||||
#define hlist_for_each(pos, head) \
|
||||
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
|
||||
pos = pos->next)
|
||||
|
||||
#define hlist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry - iterate over list of given type
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry(tpos, pos, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_continue(tpos, pos, member) \
|
||||
for (pos = (pos)->next; \
|
||||
pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_from(tpos, pos, member) \
|
||||
for (; pos && ({ prefetch(pos->next); 1;}) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
||||
* @n: another &struct hlist_node to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the hlist_node within the struct.
|
||||
*/
|
||||
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||
for (pos = (head)->first; \
|
||||
pos && ({ n = pos->next; 1; }) && \
|
||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
||||
pos = n)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* DECT Mobility Management
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _LIBDECT_MM_H
|
||||
#define _LIBDECT_MM_H
|
||||
|
||||
/**
|
||||
* MM message types
|
||||
*/
|
||||
enum dect_mm_msg_types {
|
||||
DECT_MM_AUTHENTICATION_REQUEST = 0x40,
|
||||
DECT_MM_AUTHENTICATION_REPLY = 0x41,
|
||||
DECT_MM_KEY_ALLOCATE = 0x42,
|
||||
DECT_MM_AUTHENTICATION_REJECT = 0x43,
|
||||
DECT_MM_ACCESS_RIGHTS_REQUEST = 0x44,
|
||||
DECT_MM_ACCESS_RIGHTS_ACCEPT = 0x45,
|
||||
DECT_MM_ACCESS_RIGHTS_REJECT = 0x47,
|
||||
DECT_MM_ACCESS_RIGHTS_TERMINATE_REQUEST = 0x48,
|
||||
DECT_MM_ACCESS_RIGHTS_TERMINATE_ACCEPT = 0x49,
|
||||
DECT_MM_ACCESS_RIGHTS_TERMINATE_REJECT = 0x4b,
|
||||
DECT_MM_CIPHER_REQUEST = 0x4c,
|
||||
DECT_MM_CIPHER_SUGGEST = 0x4e,
|
||||
DECT_MM_CIPHER_REJECT = 0x4f,
|
||||
DECT_MM_INFO_REQUEST = 0x50,
|
||||
DECT_MM_INFO_ACCEPT = 0x51,
|
||||
DECT_MM_INFO_SUGGEST = 0x52,
|
||||
DECT_MM_INFO_REJECT = 0x53,
|
||||
DECT_MM_LOCATE_REQUEST = 0x54,
|
||||
DECT_MM_LOCATE_ACCEPT = 0x55,
|
||||
DECT_MM_DETACH = 0x56,
|
||||
DECT_MM_LOCATE_REJECT = 0x57,
|
||||
DECT_MM_IDENTITY_REQUEST = 0x58,
|
||||
DECT_MM_IDENTITY_REPLY = 0x59,
|
||||
DECT_MM_TEMPORARY_IDENTITY_ASSIGN = 0x5c,
|
||||
DECT_MM_TEMPORARY_IDENTITY_ASSIGN_ACK = 0x5d,
|
||||
DECT_MM_TEMPORARY_IDENTITY_ASSIGN_REJ = 0x5f,
|
||||
};
|
||||
|
||||
struct dect_mm_access_rights_accept_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_access_rights_reject_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_reject_reason *reject_reason;
|
||||
struct dect_ie_duration *duration;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_mm_access_rights_request_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_auth_type *auth_type;
|
||||
struct dect_ie_cipher_info *cipher_info;
|
||||
struct dect_ie_setup_capability *setup_capability;
|
||||
struct dect_ie_terminal_capability *terminal_capability;
|
||||
struct dect_ie_iwu_to_iwu *iwu_to_iwu;
|
||||
struct dect_ie_model_identifier *model_identifier;
|
||||
struct dect_ie_codec_list *codec_list;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_mm_access_rights_terminate_accept_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_access_rights_terminate_reject_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_access_rights_terminate_request_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_authentication_reject_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_authentication_reply_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_authentication_request_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_cipher_reject_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_cipher_request_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_cipher_suggest_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_detach_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_identity_reply_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_identity_request_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_key_allocate_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_locate_accept_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_locate_reject_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_locate_request_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_info_accept_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_info_reject_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_info_request_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_info_suggest_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_temporary_identity_assign_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_temporary_identity_assign_ack_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_temporary_identity_assign_rej_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_iwu_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
struct dect_mm_notify_msg {
|
||||
struct dect_msg_common common;
|
||||
};
|
||||
|
||||
#endif /* _LIBDECT_MM_H */
|
|
@ -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 */
|
|
@ -0,0 +1,377 @@
|
|||
#ifndef _DECT_S_FMT_H
|
||||
#define _DECT_S_FMT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <identities.h>
|
||||
|
||||
/*
|
||||
* S-Format message header
|
||||
*/
|
||||
|
||||
#define DECT_S_HDR_SIZE 2
|
||||
|
||||
/* Transaction Identifier (TI) element */
|
||||
#define DECT_S_TI_F_FLAG 0x80
|
||||
|
||||
#define DECT_S_TI_TV_MASK 0x70
|
||||
#define DECT_S_TI_TV_SHIFT 4
|
||||
|
||||
#define DECT_S_TI_TV_EXT_FLAG 0x08
|
||||
|
||||
/* Protocol Descriminator (PD) element */
|
||||
#define DECT_S_PD_MASK 0x0f
|
||||
|
||||
/**
|
||||
* @DECT_S_PD_LCE: Link Control Entity (LCE) messages
|
||||
* @DECT_S_PD_CC: Call Control (CC) messages
|
||||
* @DECT_S_PD_CISS: Call Independant Supplementary Services (CISS) messages
|
||||
* @DECT_S_PD_MM: Mobility Management (MM) messages
|
||||
* @DECT_S_PD_CLMS: ConnectionLess Message Service (CLMS) messages
|
||||
* @DECT_S_PD_COMS: Connection Orentied Message Service (COMS) messages
|
||||
* @DECT_S_PD_UNKNOWN: Unknown protocol entity (bit 8)
|
||||
*/
|
||||
enum dect_s_pd_values {
|
||||
DECT_S_PD_LCE = 0x0,
|
||||
DECT_S_PD_CC = 0x3,
|
||||
DECT_S_PD_CISS = 0x4,
|
||||
DECT_S_PD_MM = 0x5,
|
||||
DECT_S_PD_CLMS = 0x6,
|
||||
DECT_S_PD_COMS = 0x7,
|
||||
DECT_S_PD_UNKNOWN = 0x8,
|
||||
__DECT_S_PD_MAX
|
||||
};
|
||||
#define DECT_S_PD_MAX (__DECT_S_PD_MAX - 1)
|
||||
|
||||
/* Message type element */
|
||||
#define DECT_S_PD_MSG_TYPE_MASK 0x7f
|
||||
|
||||
/* CLMS message types */
|
||||
enum dect_clms_msg_types {
|
||||
DECT_CLMS_VARIABLE = 0x1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Information elements
|
||||
*/
|
||||
|
||||
#define DECT_SFMT_IE_FIXED_LEN 0x80
|
||||
#define DECT_SFMT_IE_FIXED_ID_MASK 0x70
|
||||
#define DECT_SFMT_IE_FIXED_ID_SHIFT 4
|
||||
#define DECT_SFMT_IE_FIXED_VAL_MASK 0x0f
|
||||
|
||||
enum dect_sfmt_single_octet_ies {
|
||||
S_SO_IE_RESERVED = (0x00 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
|
||||
S_SO_IE_SHIFT = (0x01 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
|
||||
S_SO_IE_EXT_PREFIX = (0x02 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
|
||||
S_SO_IE_REPEAT_INDICATOR = (0x05 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
|
||||
S_SO_IE_DOUBLE_OCTET_ELEMENT = (0x06 << DECT_SFMT_IE_FIXED_ID_SHIFT) | DECT_SFMT_IE_FIXED_LEN,
|
||||
};
|
||||
|
||||
enum dect_sfmt_single_octet_ext_ies {
|
||||
S_SE_IE_SENDING_COMPLETE = 0x1 | S_SO_IE_EXT_PREFIX,
|
||||
S_SE_IE_DELIMITER_REQUEST = 0x2 | S_SO_IE_EXT_PREFIX,
|
||||
S_SE_IE_USE_TPUI = 0x3 | S_SO_IE_EXT_PREFIX,
|
||||
};
|
||||
|
||||
enum dect_sfmt_double_octet_ies {
|
||||
S_DO_IE_BASIC_SERVICE = 0x0 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
S_DO_IE_RELEASE_REASON = 0x2 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
S_DO_IE_SIGNAL = 0x4 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
S_DO_IE_TIMER_RESTART = 0x5 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
S_DO_IE_TEST_HOOK_CONTROL = 0x6 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
S_DO_IE_SINGLE_DISPLAY = 0x8 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
S_DO_IE_SINGLE_KEYPAD = 0x9 | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
S_DO_IE_RESERVED = 0xf | S_SO_IE_DOUBLE_OCTET_ELEMENT,
|
||||
};
|
||||
|
||||
enum dect_sfmt_variable_length_ies {
|
||||
S_VL_IE_INFO_TYPE = 0x01,
|
||||
S_VL_IE_IDENTITY_TYPE = 0x02,
|
||||
S_VL_IE_PORTABLE_IDENTITY = 0x05,
|
||||
S_VL_IE_FIXED_IDENTITY = 0x06,
|
||||
S_VL_IE_LOCATION_AREA = 0x07,
|
||||
S_VL_IE_NWK_ASSIGNED_IDENTITY = 0x09,
|
||||
S_VL_IE_AUTH_TYPE = 0x0a,
|
||||
S_VL_IE_ALLOCATION_TYPE = 0x0b,
|
||||
S_VL_IE_RAND = 0x0c,
|
||||
S_VL_IE_RES = 0x0d,
|
||||
S_VL_IE_RS = 0x0e,
|
||||
S_VL_IE_IWU_ATTRIBUTES = 0x12,
|
||||
S_VL_IE_CALL_ATTRIBUTES = 0x13,
|
||||
S_VL_IE_SERVICE_CHANGE_INFO = 0x16,
|
||||
S_VL_IE_CONNECTION_ATTRIBUTES = 0x17,
|
||||
S_VL_IE_CIPHER_INFO = 0x19,
|
||||
S_VL_IE_CALL_IDENTITY = 0x1a,
|
||||
S_VL_IE_CONNECTION_IDENTITY = 0x1b,
|
||||
S_VL_IE_FACILITY = 0x1c,
|
||||
S_VL_IE_PROGRESS_INDICATOR = 0x1e,
|
||||
S_VL_IE_MMS_GENERIC_HEADER = 0x20,
|
||||
S_VL_IE_MMS_OBJECT_HEADER = 0x21,
|
||||
S_VL_IE_MMS_EXTENDED_HEADER = 0x22,
|
||||
S_VL_IE_TIME_DATE = 0x23,
|
||||
S_VL_IE_MULTI_DISPLAY = 0x28,
|
||||
S_VL_IE_MULTI_KEYPAD = 0x2c,
|
||||
S_VL_IE_FEATURE_ACTIVATE = 0x38,
|
||||
S_VL_IE_FEATURE_INDICATE = 0x39,
|
||||
S_VL_IE_NETWORK_PARAMETER = 0x41,
|
||||
S_VL_IE_EXT_HO_INDICATOR = 0x42,
|
||||
S_VL_IE_ZAP_FIELD = 0x52,
|
||||
S_VL_IE_SERVICE_CLASS = 0x54,
|
||||
S_VL_IE_KEY = 0x56,
|
||||
S_VL_IE_REJECT_REASON = 0x60,
|
||||
S_VL_IE_SETUP_CAPABILITY = 0x62,
|
||||
S_VL_IE_TERMINAL_CAPABILITY = 0x63,
|
||||
S_VL_IE_END_TO_END_COMPATIBILITY = 0x64,
|
||||
S_VL_IE_RATE_PARAMETERS = 0x65,
|
||||
S_VL_IE_TRANSIT_DELAY = 0x66,
|
||||
S_VL_IE_WINDOW_SIZE = 0x67,
|
||||
S_VL_IE_CALLING_PARTY_NUMBER = 0x6c,
|
||||
S_VL_IE_CALLING_PARTY_NAME = 0x6d,
|
||||
S_VL_IE_CALLED_PARTY_NUMBER = 0x70,
|
||||
S_VL_IE_CALLED_PARTY_SUBADDR = 0x71,
|
||||
S_VL_IE_DURATION = 0x72,
|
||||
S_VL_IE_SEGMENTED_INFO = 0x75,
|
||||
S_VL_IE_ALPHANUMERIC = 0x76,
|
||||
S_VL_IE_IWU_TO_IWU = 0x77,
|
||||
S_VL_IE_MODEL_IDENTIFIER = 0x78,
|
||||
S_VL_IE_IWU_PACKET = 0x7a,
|
||||
S_VL_IE_ESCAPE_TO_PROPRIETARY = 0x7b,
|
||||
S_VL_IE_CODEC_LIST = 0x7c,
|
||||
S_VL_IE_EVENTS_NOTIFICATION = 0x7d,
|
||||
S_VL_IE_CALL_INFORMATION = 0x7e,
|
||||
S_VL_IE_ESCAPE_FOR_EXTENSION = 0x7f,
|
||||
__S_VL_IE_MAX
|
||||
};
|
||||
|
||||
/* Repeat indicator */
|
||||
|
||||
/* Basic service */
|
||||
|
||||
#define DECT_BASIC_SERVICE_CALL_CLASS_MASK 0xf0
|
||||
#define DECT_BASIC_SERVICE_CALL_CLASS_SHIFT 4
|
||||
|
||||
#define DECT_BASIC_SERVICE_SERVICE_MASK 0x0f
|
||||
|
||||
/* Single display IE */
|
||||
|
||||
/* Single keypad IE */
|
||||
|
||||
/* Release reason */
|
||||
|
||||
/* Allocation type IE */
|
||||
|
||||
/* Alphanumeric IE */
|
||||
|
||||
/* Auth type IE */
|
||||
|
||||
/* Call attributes IE */
|
||||
|
||||
/* Call identity IE */
|
||||
|
||||
/* Called party number IE */
|
||||
|
||||
/* Called party subaddress IE */
|
||||
|
||||
/* Calling party number IE */
|
||||
|
||||
/* Cipher info IE */
|
||||
|
||||
/* Connection attributes IE */
|
||||
|
||||
/* Connection identity IE */
|
||||
|
||||
/* Duration IE */
|
||||
|
||||
/* End-to-end compatibility IE */
|
||||
|
||||
/* Facility IE */
|
||||
|
||||
/* Feature activate IE */
|
||||
|
||||
/* Feature indicate IE */
|
||||
|
||||
/* Fixed identity IE */
|
||||
|
||||
#define S_VL_IE_FIXED_IDENTITY_MIN_SIZE 2
|
||||
|
||||
#define S_VL_IE_FIXED_IDENTITY_TYPE_MASK 0x7f
|
||||
#define S_VL_IE_FIXED_IDENTITY_LENGTH_MASK 0x7f
|
||||
|
||||
/* Identity type IE */
|
||||
|
||||
/* Info type IE */
|
||||
|
||||
/* InterWorking Unit (IWU) attributes IE */
|
||||
|
||||
/* IWU packet IE */
|
||||
|
||||
/* IWU to IWU IE */
|
||||
|
||||
/* Key IE */
|
||||
|
||||
/* Location area IE */
|
||||
|
||||
/* Multi-display IE */
|
||||
|
||||
/* Multi-keypad IE */
|
||||
|
||||
/* NetWorK (NWK) assigned identity IE */
|
||||
|
||||
/* Network parameter IE */
|
||||
|
||||
/* Portable identity IE */
|
||||
|
||||
#define S_VL_IE_PORTABLE_IDENTITY_MIN_SIZE 2
|
||||
|
||||
#define S_VL_IE_PORTABLE_IDENTITY_TYPE_MASK 0x7f
|
||||
#define S_VL_IE_PORTABLE_IDENTITY_LENGTH_MASK 0x7f
|
||||
|
||||
/* IPUI */
|
||||
|
||||
#define IPUI_BITS_PER_DIGIT 4
|
||||
#define IPUI_PUT_PSTN_ISDN_NUMBER_MAX_DIGITS 60
|
||||
|
||||
#define IPUI_PUT_PRIVATE_NUMBER_MAX_LEN 60
|
||||
|
||||
/* Progress indicator IE */
|
||||
|
||||
#define DECT_SFMT_IE_PROGRESS_INDICATOR_LOCATION_MASK 0x0f
|
||||
|
||||
/* RAND IE */
|
||||
|
||||
/* Rate parameters IE */
|
||||
|
||||
/* Reject reason IE */
|
||||
|
||||
/* RES IE */
|
||||
|
||||
/* RS IE */
|
||||
|
||||
/* Segmented info IE */
|
||||
|
||||
/* Service change info IE */
|
||||
|
||||
/* Service class IE */
|
||||
|
||||
/* Setup capability IE */
|
||||
|
||||
/* Terminal capability IE */
|
||||
|
||||
/* Transit delay IE */
|
||||
|
||||
/* Window size IE */
|
||||
|
||||
/* ZAP field IE */
|
||||
|
||||
/* Escape to proprietary IE */
|
||||
|
||||
#define DECT_ESC_TO_PROPRIETARY_IE_DESC_TYPE_MASK 0x7f
|
||||
#define DECT_ESC_TO_PROPRIETARY_IE_DESC_EMC 1
|
||||
|
||||
/* Model identifier IE */
|
||||
|
||||
/* MMS Generic Header IE */
|
||||
|
||||
/* MMS Object Header IE */
|
||||
|
||||
/* MMS Extended Header IE */
|
||||
|
||||
/* Time-Data IE */
|
||||
|
||||
/* Ext h/o indicator IE */
|
||||
|
||||
/* Authentication Reject Parameter IE */
|
||||
|
||||
/* Calling party Name IE */
|
||||
|
||||
/* Codec List IE */
|
||||
|
||||
/* Events notification IE */
|
||||
|
||||
/* Call information IE */
|
||||
|
||||
enum dect_sfmt_ie_status {
|
||||
DECT_SFMT_IE_NONE,
|
||||
DECT_SFMT_IE_OPTIONAL,
|
||||
DECT_SFMT_IE_MANDATORY
|
||||
};
|
||||
|
||||
enum dect_sfmt_ie_flags {
|
||||
DECT_SFMT_IE_REPEAT = 0x1,
|
||||
DECT_SFMT_IE_EITHER = 0x2,
|
||||
DECT_SFMT_IE_END = 0x4,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dect_sfmt_ie_desc - S-Format IE description
|
||||
*
|
||||
* @offset: offset of corresponding S-Format IE storage
|
||||
* @type: IE type
|
||||
* @f_p: Status in direction FP->PP
|
||||
* @p_f: Status in direction PP->FP
|
||||
* @flags: Global flags
|
||||
*/
|
||||
struct dect_sfmt_ie_desc {
|
||||
uint16_t type;
|
||||
enum dect_sfmt_ie_status f_p:8;
|
||||
enum dect_sfmt_ie_status p_f:8;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define DECT_SFMT_IE(_type, _f_p, _p_f, _flags) { \
|
||||
.type = (_type), \
|
||||
.f_p = DECT_SFMT_ ## _f_p, \
|
||||
.p_f = DECT_SFMT_ ## _p_f, \
|
||||
.flags = (_flags), \
|
||||
}
|
||||
|
||||
#define DECT_SFMT_IE_END_MSG { \
|
||||
.flags = DECT_SFMT_IE_END, \
|
||||
}
|
||||
|
||||
|
||||
struct dect_sfmt_ie {
|
||||
uint8_t *data;
|
||||
uint16_t id;
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dect_sfmt_error - S-Format message parsing/construction state
|
||||
*
|
||||
* @DECT_SFMT_OK: No error
|
||||
* @DECT_SFMT_MANDATORY_IE_MISSING: A mandatory IE was missing
|
||||
* @DECT_SFMT_MANDATORY_IE_ERROR: A mandatory IE had an internal structural error
|
||||
* @DECT_SFMT_INVALID_IE: An invalid IE was passed to message construction
|
||||
*/
|
||||
enum dect_sfmt_error {
|
||||
DECT_SFMT_OK = 0,
|
||||
DECT_SFMT_MANDATORY_IE_MISSING = -1,
|
||||
DECT_SFMT_MANDATORY_IE_ERROR = -2,
|
||||
DECT_SFMT_INVALID_IE = -3,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dect_msg_common - Common dummy msg structure to avoid casts
|
||||
*
|
||||
* @ie: First IE
|
||||
*/
|
||||
struct dect_msg_common {
|
||||
struct dect_ie_common *ie[0];
|
||||
};
|
||||
|
||||
struct dect_msg_buf;
|
||||
extern enum dect_sfmt_error dect_parse_sfmt_msg(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
struct dect_msg_common *dst,
|
||||
struct dect_msg_buf *mb);
|
||||
extern enum dect_sfmt_error dect_build_sfmt_msg(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
const struct dect_msg_common *src,
|
||||
struct dect_msg_buf *mb);
|
||||
|
||||
extern void dect_msg_free(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
struct dect_msg_common *msg);
|
||||
|
||||
#endif /* _DECT_S_FMT_H */
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* DECT Supplementary Services (SS)
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*/
|
||||
|
||||
#ifndef _DECT_SS_H
|
||||
#define _DECT_SS_H
|
||||
|
||||
/**
|
||||
* Call Independant Supplementary Services messages types
|
||||
*/
|
||||
enum dect_ciss_msg_types {
|
||||
CISS_RELEASE_COM = 0x5a,
|
||||
CISS_FACILITY = 0x62,
|
||||
CISS_REGISTER = 0x64,
|
||||
};
|
||||
|
||||
struct dect_ciss_release_com_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_release_reason *release_reason;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
struct dect_ciss_facility_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_repeat_indicator iwu_to_iwu;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
struct dect_ie_time_date *time_date;
|
||||
struct dect_ie_events_notification *events_notification;
|
||||
struct dect_ie_call_information *call_information;
|
||||
};
|
||||
|
||||
struct dect_ciss_register_msg {
|
||||
struct dect_msg_common common;
|
||||
struct dect_ie_portable_identity *portable_identity;
|
||||
struct dect_ie_repeat_indicator facility;
|
||||
struct dect_ie_display *display;
|
||||
struct dect_ie_keypad *keypad;
|
||||
struct dect_ie_feature_activate *feature_activate;
|
||||
struct dect_ie_feature_indicate *feature_indicate;
|
||||
struct dect_ie_escape_to_proprietary *escape_to_proprietary;
|
||||
};
|
||||
|
||||
extern void dect_clss_rcv(struct dect_handle *dh, struct dect_msg_buf *mb);
|
||||
|
||||
/**
|
||||
* Call Related Supplementary Services messages types
|
||||
*/
|
||||
enum dect_crss_msg_types {
|
||||
CRSS_HOLD = 0x24,
|
||||
CRSS_HOLD_ACK = 0x28,
|
||||
CRSS_HOLD_REJECT = 0x30,
|
||||
CRSS_RETRIEVE = 0x31,
|
||||
CRSS_RETRIEVE_ACK = 0x33,
|
||||
CRSS_RETRIEVE_REJECT = 0x37,
|
||||
CRSS_FACILITY = 0x62,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef _UITLS_H
|
||||
#define _UTILS_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef AF_DECT
|
||||
#define AF_DECT 36
|
||||
#endif
|
||||
|
||||
#define __init __attribute__((constructor))
|
||||
#define __exit __attribute__((destructor))
|
||||
#define __must_check __attribute__((warn_unused_result))
|
||||
#define __noreturn __attribute__((__noreturn__))
|
||||
#define __fmtstring(x, y) __attribute__((format(printf, x, y)))
|
||||
#define __aligned(x) __attribute__((aligned(x)))
|
||||
#define __packed __attribute__((packed))
|
||||
|
||||
extern void *dect_malloc(const struct dect_handle *dh, size_t size);
|
||||
extern void *dect_zalloc(const struct dect_handle *dh, size_t size);
|
||||
extern void dect_free(const struct dect_handle *dh, void *ptr);
|
||||
|
||||
extern struct dect_timer *dect_alloc_timer(const struct dect_handle *dh);
|
||||
extern void dect_start_timer(const struct dect_handle *dh,
|
||||
struct dect_timer *timer, unsigned int timeout);
|
||||
extern void dect_stop_timer(const struct dect_handle *dh, struct dect_timer *timer);
|
||||
|
||||
struct dect_fd *dect_alloc_fd(const struct dect_handle *dh);
|
||||
extern void dect_close(const struct dect_handle *dh, struct dect_fd *dfd);
|
||||
|
||||
extern void dect_debug(const char *fmt, ...) __fmtstring(1, 2);
|
||||
extern void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size);
|
||||
|
||||
#include <sys/socket.h> // FIXME: socklen_t
|
||||
extern struct dect_fd *dect_socket(const struct dect_handle *dh,
|
||||
int type, int protocol);
|
||||
extern struct dect_fd *dect_accept(const struct dect_handle *dh,
|
||||
const struct dect_fd *dfd,
|
||||
struct sockaddr *addr, socklen_t len);
|
||||
|
||||
extern int dect_register_fd(const struct dect_handle *dh, struct dect_fd *dfd,
|
||||
uint32_t events);
|
||||
extern void dect_unregister_fd(const struct dect_handle *dh, struct dect_fd *dfd);
|
||||
|
||||
#define BUG() assert(0)
|
||||
|
||||
/* Force a compilation error if condition is true */
|
||||
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
|
||||
#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
|
||||
|
||||
#define __must_be_array(a) \
|
||||
BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
|
||||
|
||||
#define array_size(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
|
||||
#define field_sizeof(t, f) (sizeof(((t *)NULL)->f))
|
||||
|
||||
#define div_round_up(n, d) (((n) + (d) - 1) / (d))
|
||||
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
#define max(x, y) ({ \
|
||||
typeof(x) _max1 = (x); \
|
||||
typeof(y) _max2 = (y); \
|
||||
(void) (&_max1 == &_max2); \
|
||||
_max1 > _max2 ? _max1 : _max2; })
|
||||
|
||||
#endif /* _UTILS_H */
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
libdect.so
|
|
@ -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
|
|
@ -0,0 +1,94 @@
|
|||
The files in this directory comprise ANSI-C language reference implementations
|
||||
of the CCITT (International Telegraph and Telephone Consultative Committee)
|
||||
G.711, G.721 and G.723 voice compressions. They have been tested on Sun
|
||||
SPARCstations and passed 82 out of 84 test vectors published by CCITT
|
||||
(Dec. 20, 1988) for G.721 and G.723. [The two remaining test vectors,
|
||||
which the G.721 decoder implementation for u-law samples did not pass,
|
||||
may be in error because they are identical to two other vectors for G.723_40.]
|
||||
|
||||
This source code is released by Sun Microsystems, Inc. to the public domain.
|
||||
Please give your acknowledgement in product literature if this code is used
|
||||
in your product implementation.
|
||||
|
||||
Sun Microsystems supports some CCITT audio formats in Solaris 2.0 system
|
||||
software. However, Sun's implementations have been optimized for higher
|
||||
performance on SPARCstations.
|
||||
|
||||
|
||||
The source files for CCITT conversion routines in this directory are:
|
||||
|
||||
g72x.h header file for g721.c, g723_24.c and g723_40.c
|
||||
g711.c CCITT G.711 u-law and A-law compression
|
||||
g72x.c common denominator of G.721 and G.723 ADPCM codes
|
||||
g721.c CCITT G.721 32Kbps ADPCM coder (with g72x.c)
|
||||
g723_24.c CCITT G.723 24Kbps ADPCM coder (with g72x.c)
|
||||
g723_40.c CCITT G.723 40Kbps ADPCM coder (with g72x.c)
|
||||
|
||||
|
||||
Simple conversions between u-law, A-law, and 16-bit linear PCM are invoked
|
||||
as follows:
|
||||
|
||||
unsigned char ucode, acode;
|
||||
short pcm_val;
|
||||
|
||||
ucode = linear2ulaw(pcm_val);
|
||||
ucode = alaw2ulaw(acode);
|
||||
|
||||
acode = linear2alaw(pcm_val);
|
||||
acode = ulaw2alaw(ucode);
|
||||
|
||||
pcm_val = ulaw2linear(ucode);
|
||||
pcm_val = alaw2linear(acode);
|
||||
|
||||
|
||||
The other CCITT compression routines are invoked as follows:
|
||||
|
||||
#include "g72x.h"
|
||||
|
||||
struct g72x_state state;
|
||||
int sample, code;
|
||||
|
||||
g72x_init_state(&state);
|
||||
code = {g721,g723_24,g723_40}_encoder(sample, coding, &state);
|
||||
sample = {g721,g723_24,g723_40}_decoder(code, coding, &state);
|
||||
|
||||
where
|
||||
coding = AUDIO_ENCODING_ULAW for 8-bit u-law samples
|
||||
AUDIO_ENCODING_ALAW for 8-bit A-law samples
|
||||
AUDIO_ENCODING_LINEAR for 16-bit linear PCM samples
|
||||
|
||||
|
||||
|
||||
This directory also includes the following sample programs:
|
||||
|
||||
encode.c CCITT ADPCM encoder
|
||||
decode.c CCITT ADPCM decoder
|
||||
Makefile makefile for the sample programs
|
||||
|
||||
|
||||
The sample programs contain examples of how to call the various compression
|
||||
routines and pack/unpack the bits. The sample programs read byte streams from
|
||||
stdin and write to stdout. The input/output data is raw data (no file header
|
||||
or other identifying information is embedded). The sample programs are
|
||||
invoked as follows:
|
||||
|
||||
encode [-3|4|5] [-a|u|l] <infile >outfile
|
||||
decode [-3|4|5] [-a|u|l] <infile >outfile
|
||||
where:
|
||||
-3 encode to (decode from) G.723 24kbps (3-bit) data
|
||||
-4 encode to (decode from) G.721 32kbps (4-bit) data [the default]
|
||||
-5 encode to (decode from) G.723 40kbps (5-bit) data
|
||||
-a encode from (decode to) A-law data
|
||||
-u encode from (decode to) u-law data [the default]
|
||||
-l encode from (decode to) 16-bit linear data
|
||||
|
||||
Examples:
|
||||
# Read 16-bit linear and output G.721
|
||||
encode -4 -l <pcmfile >g721file
|
||||
|
||||
# Read 40Kbps G.723 and output A-law
|
||||
decode -5 -a <g723file >alawfile
|
||||
|
||||
# Compress and then decompress u-law data using 24Kbps G.723
|
||||
encode -3 <ulawin | deoced -3 >ulawout
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* decode.c
|
||||
*
|
||||
* CCITT ADPCM decoder
|
||||
*
|
||||
* Usage : decode [-3|4|5] [-a|u|l] < infile > outfile
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "g72x.h"
|
||||
|
||||
|
||||
/*
|
||||
* Unpack input codes and pass them back as bytes.
|
||||
* Returns 1 if there is residual input, returns -1 if eof, else returns 0.
|
||||
*/
|
||||
int
|
||||
unpack_input(
|
||||
unsigned char *code,
|
||||
int bits)
|
||||
{
|
||||
static unsigned int in_buffer = 0;
|
||||
static int in_bits = 0;
|
||||
unsigned char in_byte;
|
||||
|
||||
if (in_bits < bits) {
|
||||
if (fread(&in_byte, sizeof (char), 1, stdin) != 1) {
|
||||
*code = 0;
|
||||
return (-1);
|
||||
}
|
||||
in_buffer |= (in_byte << in_bits);
|
||||
in_bits += 8;
|
||||
}
|
||||
*code = in_buffer & ((1 << bits) - 1);
|
||||
in_buffer >>= bits;
|
||||
in_bits -= bits;
|
||||
return (in_bits > 0);
|
||||
}
|
||||
|
||||
|
||||
main(
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
short sample;
|
||||
unsigned char code;
|
||||
int n;
|
||||
struct g72x_state state;
|
||||
int out_coding;
|
||||
int out_size;
|
||||
int (*dec_routine)();
|
||||
int dec_bits;
|
||||
|
||||
g72x_init_state(&state);
|
||||
out_coding = AUDIO_ENCODING_ULAW;
|
||||
out_size = sizeof (char);
|
||||
dec_routine = g721_decoder;
|
||||
dec_bits = 4;
|
||||
|
||||
/* Process encoding argument, if any */
|
||||
while ((argc > 1) && (argv[1][0] == '-')) {
|
||||
switch (argv[1][1]) {
|
||||
case '3':
|
||||
dec_routine = g723_24_decoder;
|
||||
dec_bits = 3;
|
||||
break;
|
||||
case '4':
|
||||
dec_routine = g721_decoder;
|
||||
dec_bits = 4;
|
||||
break;
|
||||
case '5':
|
||||
dec_routine = g723_40_decoder;
|
||||
dec_bits = 5;
|
||||
break;
|
||||
case 'u':
|
||||
out_coding = AUDIO_ENCODING_ULAW;
|
||||
out_size = sizeof (char);
|
||||
break;
|
||||
case 'a':
|
||||
out_coding = AUDIO_ENCODING_ALAW;
|
||||
out_size = sizeof (char);
|
||||
break;
|
||||
case 'l':
|
||||
out_coding = AUDIO_ENCODING_LINEAR;
|
||||
out_size = sizeof (short);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "CCITT ADPCM Decoder -- usage:\n");
|
||||
fprintf(stderr, "\tdecode [-3|4|5] [-a|u|l] < infile > outfile\n");
|
||||
fprintf(stderr, "where:\n");
|
||||
fprintf(stderr, "\t-3\tProcess G.723 24kbps (3-bit) input data\n");
|
||||
fprintf(stderr, "\t-4\tProcess G.721 32kbps (4-bit) input data [default]\n");
|
||||
fprintf(stderr, "\t-5\tProcess G.723 40kbps (5-bit) input data\n");
|
||||
fprintf(stderr, "\t-a\tGenerate 8-bit A-law data\n");
|
||||
fprintf(stderr, "\t-u\tGenerate 8-bit u-law data [default]\n");
|
||||
fprintf(stderr, "\t-l\tGenerate 16-bit linear PCM data\n");
|
||||
exit(1);
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
/* Read and unpack input codes and process them */
|
||||
while (unpack_input(&code, dec_bits) >= 0) {
|
||||
sample = (*dec_routine)(code, out_coding, &state);
|
||||
if (out_size == 2) {
|
||||
fwrite(&sample, out_size, 1, stdout);
|
||||
} else {
|
||||
code = (unsigned char)sample;
|
||||
fwrite(&code, out_size, 1, stdout);
|
||||
}
|
||||
}
|
||||
fclose(stdout);
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* encode.c
|
||||
*
|
||||
* CCITT ADPCM encoder
|
||||
*
|
||||
* Usage : encode [-3|4|5] [-a|u|l] < infile > outfile
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "g72x.h"
|
||||
|
||||
|
||||
/*
|
||||
* Pack output codes into bytes and write them to stdout.
|
||||
* Returns 1 if there is residual output, else returns 0.
|
||||
*/
|
||||
int
|
||||
pack_output(
|
||||
unsigned code,
|
||||
int bits)
|
||||
{
|
||||
static unsigned int out_buffer = 0;
|
||||
static int out_bits = 0;
|
||||
unsigned char out_byte;
|
||||
|
||||
out_buffer |= (code << out_bits);
|
||||
out_bits += bits;
|
||||
if (out_bits >= 8) {
|
||||
out_byte = out_buffer & 0xff;
|
||||
out_bits -= 8;
|
||||
out_buffer >>= 8;
|
||||
fwrite(&out_byte, sizeof (char), 1, stdout);
|
||||
}
|
||||
return (out_bits > 0);
|
||||
}
|
||||
|
||||
|
||||
main(
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
struct g72x_state state;
|
||||
unsigned char sample_char;
|
||||
short sample_short;
|
||||
unsigned char code;
|
||||
int resid;
|
||||
int in_coding;
|
||||
int in_size;
|
||||
unsigned *in_buf;
|
||||
int (*enc_routine)();
|
||||
int enc_bits;
|
||||
|
||||
g72x_init_state(&state);
|
||||
|
||||
/* Set defaults to u-law input, G.721 output */
|
||||
in_coding = AUDIO_ENCODING_ULAW;
|
||||
in_size = sizeof (char);
|
||||
in_buf = (unsigned *)&sample_char;
|
||||
enc_routine = g721_encoder;
|
||||
enc_bits = 4;
|
||||
|
||||
/* Process encoding argument, if any */
|
||||
while ((argc > 1) && (argv[1][0] == '-')) {
|
||||
switch (argv[1][1]) {
|
||||
case '3':
|
||||
enc_routine = g723_24_encoder;
|
||||
enc_bits = 3;
|
||||
break;
|
||||
case '4':
|
||||
enc_routine = g721_encoder;
|
||||
enc_bits = 4;
|
||||
break;
|
||||
case '5':
|
||||
enc_routine = g723_40_encoder;
|
||||
enc_bits = 5;
|
||||
break;
|
||||
case 'u':
|
||||
in_coding = AUDIO_ENCODING_ULAW;
|
||||
in_size = sizeof (char);
|
||||
in_buf = (unsigned *)&sample_char;
|
||||
break;
|
||||
case 'a':
|
||||
in_coding = AUDIO_ENCODING_ALAW;
|
||||
in_size = sizeof (char);
|
||||
in_buf = (unsigned *)&sample_char;
|
||||
break;
|
||||
case 'l':
|
||||
in_coding = AUDIO_ENCODING_LINEAR;
|
||||
in_size = sizeof (short);
|
||||
in_buf = (unsigned *)&sample_short;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "CCITT ADPCM Encoder -- usage:\n");
|
||||
fprintf(stderr, "\tencode [-3|4|5] [-a|u|l] < infile > outfile\n");
|
||||
fprintf(stderr, "where:\n");
|
||||
fprintf(stderr, "\t-3\tGenerate G.723 24kbps (3-bit) data\n");
|
||||
fprintf(stderr, "\t-4\tGenerate G.721 32kbps (4-bit) data [default]\n");
|
||||
fprintf(stderr, "\t-5\tGenerate G.723 40kbps (5-bit) data\n");
|
||||
fprintf(stderr, "\t-a\tProcess 8-bit A-law input data\n");
|
||||
fprintf(stderr, "\t-u\tProcess 8-bit u-law input data [default]\n");
|
||||
fprintf(stderr, "\t-l\tProcess 16-bit linear PCM input data\n");
|
||||
exit(1);
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
/* Read input file and process */
|
||||
while (fread(in_buf, in_size, 1, stdin) == 1) {
|
||||
code = (*enc_routine)(in_size == 2 ? sample_short : sample_char,
|
||||
in_coding, &state);
|
||||
resid = pack_output(code, enc_bits);
|
||||
}
|
||||
|
||||
/* Write zero codes until all residual codes are written out */
|
||||
while (resid) {
|
||||
resid = pack_output(0, enc_bits);
|
||||
}
|
||||
fclose(stdout);
|
||||
}
|
|
@ -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)));
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,565 @@
|
|||
/*
|
||||
* This source code is a product of Sun Microsystems, Inc. and is provided
|
||||
* for unrestricted use. Users may copy or modify this source code without
|
||||
* charge.
|
||||
*
|
||||
* SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
|
||||
* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
|
||||
*
|
||||
* Sun source code is provided with no support and without any obligation on
|
||||
* the part of Sun Microsystems, Inc. to assist in its use, correction,
|
||||
* modification or enhancement.
|
||||
*
|
||||
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
|
||||
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
|
||||
* OR ANY PART THEREOF.
|
||||
*
|
||||
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
|
||||
* or profits or other special, indirect and consequential damages, even if
|
||||
* Sun has been advised of the possibility of such damages.
|
||||
*
|
||||
* Sun Microsystems, Inc.
|
||||
* 2550 Garcia Avenue
|
||||
* Mountain View, California 94043
|
||||
*/
|
||||
|
||||
/*
|
||||
* g72x.c
|
||||
*
|
||||
* Common routines for G.721 and G.723 conversions.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "g72x.h"
|
||||
|
||||
static short power2[15] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
|
||||
0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000};
|
||||
|
||||
/*
|
||||
* quan()
|
||||
*
|
||||
* quantizes the input val against the table of size short integers.
|
||||
* It returns i if table[i - 1] <= val < table[i].
|
||||
*
|
||||
* Using linear search for simple coding.
|
||||
*/
|
||||
static int
|
||||
quan(
|
||||
int val,
|
||||
short *table,
|
||||
int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
if (val < *table++)
|
||||
break;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* fmult()
|
||||
*
|
||||
* returns the integer product of the 14-bit integer "an" and
|
||||
* "floating point" representation (4-bit exponent, 6-bit mantessa) "srn".
|
||||
*/
|
||||
static int
|
||||
fmult(
|
||||
int an,
|
||||
int srn)
|
||||
{
|
||||
short anmag, anexp, anmant;
|
||||
short wanexp, wanmant;
|
||||
short retval;
|
||||
|
||||
anmag = (an > 0) ? an : ((-an) & 0x1FFF);
|
||||
anexp = quan(anmag, power2, 15) - 6;
|
||||
anmant = (anmag == 0) ? 32 :
|
||||
(anexp >= 0) ? anmag >> anexp : anmag << -anexp;
|
||||
wanexp = anexp + ((srn >> 6) & 0xF) - 13;
|
||||
|
||||
wanmant = (anmant * (srn & 077) + 0x30) >> 4;
|
||||
retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) :
|
||||
(wanmant >> -wanexp);
|
||||
|
||||
return (((an ^ srn) < 0) ? -retval : retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* g72x_init_state()
|
||||
*
|
||||
* This routine initializes and/or resets the g72x_state structure
|
||||
* pointed to by 'state_ptr'.
|
||||
* All the initial state values are specified in the CCITT G.721 document.
|
||||
*/
|
||||
void
|
||||
g72x_init_state(
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
int cnta;
|
||||
|
||||
state_ptr->yl = 34816;
|
||||
state_ptr->yu = 544;
|
||||
state_ptr->dms = 0;
|
||||
state_ptr->dml = 0;
|
||||
state_ptr->ap = 0;
|
||||
for (cnta = 0; cnta < 2; cnta++) {
|
||||
state_ptr->a[cnta] = 0;
|
||||
state_ptr->pk[cnta] = 0;
|
||||
state_ptr->sr[cnta] = 32;
|
||||
}
|
||||
for (cnta = 0; cnta < 6; cnta++) {
|
||||
state_ptr->b[cnta] = 0;
|
||||
state_ptr->dq[cnta] = 32;
|
||||
}
|
||||
state_ptr->td = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* predictor_zero()
|
||||
*
|
||||
* computes the estimated signal from 6-zero predictor.
|
||||
*
|
||||
*/
|
||||
int
|
||||
predictor_zero(
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
int i;
|
||||
int sezi;
|
||||
|
||||
sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);
|
||||
for (i = 1; i < 6; i++) /* ACCUM */
|
||||
sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);
|
||||
return (sezi);
|
||||
}
|
||||
/*
|
||||
* predictor_pole()
|
||||
*
|
||||
* computes the estimated signal from 2-pole predictor.
|
||||
*
|
||||
*/
|
||||
int
|
||||
predictor_pole(
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +
|
||||
fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));
|
||||
}
|
||||
/*
|
||||
* step_size()
|
||||
*
|
||||
* computes the quantization step size of the adaptive quantizer.
|
||||
*
|
||||
*/
|
||||
int
|
||||
step_size(
|
||||
struct g72x_state *state_ptr)
|
||||
{
|
||||
int y;
|
||||
int dif;
|
||||
int al;
|
||||
|
||||
if (state_ptr->ap >= 256)
|
||||
return (state_ptr->yu);
|
||||
else {
|
||||
y = state_ptr->yl >> 6;
|
||||
dif = state_ptr->yu - y;
|
||||
al = state_ptr->ap >> 2;
|
||||
if (dif > 0)
|
||||
y += (dif * al) >> 6;
|
||||
else if (dif < 0)
|
||||
y += (dif * al + 0x3F) >> 6;
|
||||
return (y);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* quantize()
|
||||
*
|
||||
* Given a raw sample, 'd', of the difference signal and a
|
||||
* quantization step size scale factor, 'y', this routine returns the
|
||||
* ADPCM codeword to which that sample gets quantized. The step
|
||||
* size scale factor division operation is done in the log base 2 domain
|
||||
* as a subtraction.
|
||||
*/
|
||||
int
|
||||
quantize(
|
||||
int d, /* Raw difference signal sample */
|
||||
int y, /* Step size multiplier */
|
||||
short *table, /* quantization table */
|
||||
int size) /* table size of short integers */
|
||||
{
|
||||
short dqm; /* Magnitude of 'd' */
|
||||
short exp; /* Integer part of base 2 log of 'd' */
|
||||
short mant; /* Fractional part of base 2 log */
|
||||
short dl; /* Log of magnitude of 'd' */
|
||||
short dln; /* Step size scale factor normalized log */
|
||||
int i;
|
||||
|
||||
/*
|
||||
* LOG
|
||||
*
|
||||
* Compute base 2 log of 'd', and store in 'dl'.
|
||||
*/
|
||||
dqm = abs(d);
|
||||
exp = quan(dqm >> 1, power2, 15);
|
||||
mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */
|
||||
dl = (exp << 7) + mant;
|
||||
|
||||
/*
|
||||
* SUBTB
|
||||
*
|
||||
* "Divide" by step size multiplier.
|
||||
*/
|
||||
dln = dl - (y >> 2);
|
||||
|
||||
/*
|
||||
* QUAN
|
||||
*
|
||||
* Obtain codword i for 'd'.
|
||||
*/
|
||||
i = quan(dln, table, size);
|
||||
if (d < 0) /* take 1's complement of i */
|
||||
return ((size << 1) + 1 - i);
|
||||
else if (i == 0) /* take 1's complement of 0 */
|
||||
return ((size << 1) + 1); /* new in 1988 */
|
||||
else
|
||||
return (i);
|
||||
}
|
||||
/*
|
||||
* reconstruct()
|
||||
*
|
||||
* Returns reconstructed difference signal 'dq' obtained from
|
||||
* codeword 'i' and quantization step size scale factor 'y'.
|
||||
* Multiplication is performed in log base 2 domain as addition.
|
||||
*/
|
||||
int
|
||||
reconstruct(
|
||||
int sign, /* 0 for non-negative value */
|
||||
int dqln, /* G.72x codeword */
|
||||
int y) /* Step size multiplier */
|
||||
{
|
||||
short dql; /* Log of 'dq' magnitude */
|
||||
short dex; /* Integer part of log */
|
||||
short dqt;
|
||||
short dq; /* Reconstructed difference signal sample */
|
||||
|
||||
dql = dqln + (y >> 2); /* ADDA */
|
||||
|
||||
if (dql < 0) {
|
||||
return ((sign) ? -0x8000 : 0);
|
||||
} else { /* ANTILOG */
|
||||
dex = (dql >> 7) & 15;
|
||||
dqt = 128 + (dql & 127);
|
||||
dq = (dqt << 7) >> (14 - dex);
|
||||
return ((sign) ? (dq - 0x8000) : dq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update()
|
||||
*
|
||||
* updates the state variables for each output code
|
||||
*/
|
||||
void
|
||||
update(
|
||||
int code_size, /* distinguish 723_40 with others */
|
||||
int y, /* quantizer step size */
|
||||
int wi, /* scale factor multiplier */
|
||||
int fi, /* for long/short term energies */
|
||||
int dq, /* quantized prediction difference */
|
||||
int sr, /* reconstructed signal */
|
||||
int dqsez, /* difference from 2-pole predictor */
|
||||
struct g72x_state *state_ptr) /* coder state pointer */
|
||||
{
|
||||
int cnt;
|
||||
short mag, exp; /* Adaptive predictor, FLOAT A */
|
||||
short a2p = 0; /* LIMC */
|
||||
short a1ul; /* UPA1 */
|
||||
short pks1; /* UPA2 */
|
||||
short fa1;
|
||||
char tr; /* tone/transition detector */
|
||||
short ylint, thr2, dqthr;
|
||||
short ylfrac, thr1;
|
||||
short pk0;
|
||||
|
||||
pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */
|
||||
|
||||
mag = dq & 0x7FFF; /* prediction difference magnitude */
|
||||
/* TRANS */
|
||||
ylint = state_ptr->yl >> 15; /* exponent part of yl */
|
||||
ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */
|
||||
thr1 = (32 + ylfrac) << ylint; /* threshold */
|
||||
thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */
|
||||
dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */
|
||||
if (state_ptr->td == 0) /* signal supposed voice */
|
||||
tr = 0;
|
||||
else if (mag <= dqthr) /* supposed data, but small mag */
|
||||
tr = 0; /* treated as voice */
|
||||
else /* signal is data (modem) */
|
||||
tr = 1;
|
||||
|
||||
/*
|
||||
* Quantizer scale factor adaptation.
|
||||
*/
|
||||
|
||||
/* FUNCTW & FILTD & DELAY */
|
||||
/* update non-steady state step size multiplier */
|
||||
state_ptr->yu = y + ((wi - y) >> 5);
|
||||
|
||||
/* LIMB */
|
||||
if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */
|
||||
state_ptr->yu = 544;
|
||||
else if (state_ptr->yu > 5120)
|
||||
state_ptr->yu = 5120;
|
||||
|
||||
/* FILTE & DELAY */
|
||||
/* update steady state step size multiplier */
|
||||
state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);
|
||||
|
||||
/*
|
||||
* Adaptive predictor coefficients.
|
||||
*/
|
||||
if (tr == 1) { /* reset a's and b's for modem signal */
|
||||
state_ptr->a[0] = 0;
|
||||
state_ptr->a[1] = 0;
|
||||
state_ptr->b[0] = 0;
|
||||
state_ptr->b[1] = 0;
|
||||
state_ptr->b[2] = 0;
|
||||
state_ptr->b[3] = 0;
|
||||
state_ptr->b[4] = 0;
|
||||
state_ptr->b[5] = 0;
|
||||
} else { /* update a's and b's */
|
||||
pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */
|
||||
|
||||
/* update predictor pole a[1] */
|
||||
a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);
|
||||
if (dqsez != 0) {
|
||||
fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];
|
||||
if (fa1 < -8191) /* a2p = function of fa1 */
|
||||
a2p -= 0x100;
|
||||
else if (fa1 > 8191)
|
||||
a2p += 0xFF;
|
||||
else
|
||||
a2p += fa1 >> 5;
|
||||
|
||||
if (pk0 ^ state_ptr->pk[1])
|
||||
/* LIMC */
|
||||
if (a2p <= -12160)
|
||||
a2p = -12288;
|
||||
else if (a2p >= 12416)
|
||||
a2p = 12288;
|
||||
else
|
||||
a2p -= 0x80;
|
||||
else if (a2p <= -12416)
|
||||
a2p = -12288;
|
||||
else if (a2p >= 12160)
|
||||
a2p = 12288;
|
||||
else
|
||||
a2p += 0x80;
|
||||
}
|
||||
|
||||
/* TRIGB & DELAY */
|
||||
state_ptr->a[1] = a2p;
|
||||
|
||||
/* UPA1 */
|
||||
/* update predictor pole a[0] */
|
||||
state_ptr->a[0] -= state_ptr->a[0] >> 8;
|
||||
if (dqsez != 0) {
|
||||
if (pks1 == 0)
|
||||
state_ptr->a[0] += 192;
|
||||
else
|
||||
state_ptr->a[0] -= 192;
|
||||
}
|
||||
|
||||
/* LIMD */
|
||||
a1ul = 15360 - a2p;
|
||||
if (state_ptr->a[0] < -a1ul)
|
||||
state_ptr->a[0] = -a1ul;
|
||||
else if (state_ptr->a[0] > a1ul)
|
||||
state_ptr->a[0] = a1ul;
|
||||
|
||||
/* UPB : update predictor zeros b[6] */
|
||||
for (cnt = 0; cnt < 6; cnt++) {
|
||||
if (code_size == 5) /* for 40Kbps G.723 */
|
||||
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;
|
||||
else /* for G.721 and 24Kbps G.723 */
|
||||
state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;
|
||||
if (dq & 0x7FFF) { /* XOR */
|
||||
if ((dq ^ state_ptr->dq[cnt]) >= 0)
|
||||
state_ptr->b[cnt] += 128;
|
||||
else
|
||||
state_ptr->b[cnt] -= 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (cnt = 5; cnt > 0; cnt--)
|
||||
state_ptr->dq[cnt] = state_ptr->dq[cnt-1];
|
||||
/* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */
|
||||
if (mag == 0) {
|
||||
state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;
|
||||
} else {
|
||||
exp = quan(mag, power2, 15);
|
||||
state_ptr->dq[0] = (dq >= 0) ?
|
||||
(exp << 6) + ((mag << 6) >> exp) :
|
||||
(exp << 6) + ((mag << 6) >> exp) - 0x400;
|
||||
}
|
||||
|
||||
state_ptr->sr[1] = state_ptr->sr[0];
|
||||
/* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */
|
||||
if (sr == 0) {
|
||||
state_ptr->sr[0] = 0x20;
|
||||
} else if (sr > 0) {
|
||||
exp = quan(sr, power2, 15);
|
||||
state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);
|
||||
} else if (sr > -32768) {
|
||||
mag = -sr;
|
||||
exp = quan(mag, power2, 15);
|
||||
state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;
|
||||
} else
|
||||
state_ptr->sr[0] = 0xFC20;
|
||||
|
||||
/* DELAY A */
|
||||
state_ptr->pk[1] = state_ptr->pk[0];
|
||||
state_ptr->pk[0] = pk0;
|
||||
|
||||
/* TONE */
|
||||
if (tr == 1) /* this sample has been treated as data */
|
||||
state_ptr->td = 0; /* next one will be treated as voice */
|
||||
else if (a2p < -11776) /* small sample-to-sample correlation */
|
||||
state_ptr->td = 1; /* signal may be data */
|
||||
else /* signal is voice */
|
||||
state_ptr->td = 0;
|
||||
|
||||
/*
|
||||
* Adaptation speed control.
|
||||
*/
|
||||
state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */
|
||||
state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */
|
||||
|
||||
if (tr == 1)
|
||||
state_ptr->ap = 256;
|
||||
else if (y < 1536) /* SUBTC */
|
||||
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
|
||||
else if (state_ptr->td == 1)
|
||||
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
|
||||
else if (abs((state_ptr->dms << 2) - state_ptr->dml) >=
|
||||
(state_ptr->dml >> 3))
|
||||
state_ptr->ap += (0x200 - state_ptr->ap) >> 4;
|
||||
else
|
||||
state_ptr->ap += (-state_ptr->ap) >> 4;
|
||||
}
|
||||
|
||||
/*
|
||||
* tandem_adjust(sr, se, y, i, sign)
|
||||
*
|
||||
* At the end of ADPCM decoding, it simulates an encoder which may be receiving
|
||||
* the output of this decoder as a tandem process. If the output of the
|
||||
* simulated encoder differs from the input to this decoder, the decoder output
|
||||
* is adjusted by one level of A-law or u-law codes.
|
||||
*
|
||||
* Input:
|
||||
* sr decoder output linear PCM sample,
|
||||
* se predictor estimate sample,
|
||||
* y quantizer step size,
|
||||
* i decoder input code,
|
||||
* sign sign bit of code i
|
||||
*
|
||||
* Return:
|
||||
* adjusted A-law or u-law compressed sample.
|
||||
*/
|
||||
int
|
||||
tandem_adjust_alaw(
|
||||
int sr, /* decoder output linear PCM sample */
|
||||
int se, /* predictor estimate sample */
|
||||
int y, /* quantizer step size */
|
||||
int i, /* decoder input code */
|
||||
int sign,
|
||||
short *qtab)
|
||||
{
|
||||
unsigned char sp; /* A-law compressed 8-bit code */
|
||||
short dx; /* prediction error */
|
||||
char id; /* quantized prediction error */
|
||||
int sd; /* adjusted A-law decoded sample value */
|
||||
int im; /* biased magnitude of i */
|
||||
int imx; /* biased magnitude of id */
|
||||
|
||||
if (sr <= -32768)
|
||||
sr = -1;
|
||||
sp = linear2alaw((sr >> 1) << 3); /* short to A-law compression */
|
||||
dx = (alaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
|
||||
id = quantize(dx, y, qtab, sign - 1);
|
||||
|
||||
if (id == i) { /* no adjustment on sp */
|
||||
return (sp);
|
||||
} else { /* sp adjustment needed */
|
||||
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
|
||||
im = i ^ sign; /* 2's complement to biased unsigned */
|
||||
imx = id ^ sign;
|
||||
|
||||
if (imx > im) { /* sp adjusted to next lower value */
|
||||
if (sp & 0x80) {
|
||||
sd = (sp == 0xD5) ? 0x55 :
|
||||
((sp ^ 0x55) - 1) ^ 0x55;
|
||||
} else {
|
||||
sd = (sp == 0x2A) ? 0x2A :
|
||||
((sp ^ 0x55) + 1) ^ 0x55;
|
||||
}
|
||||
} else { /* sp adjusted to next higher value */
|
||||
if (sp & 0x80)
|
||||
sd = (sp == 0xAA) ? 0xAA :
|
||||
((sp ^ 0x55) + 1) ^ 0x55;
|
||||
else
|
||||
sd = (sp == 0x55) ? 0xD5 :
|
||||
((sp ^ 0x55) - 1) ^ 0x55;
|
||||
}
|
||||
return (sd);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tandem_adjust_ulaw(
|
||||
int sr, /* decoder output linear PCM sample */
|
||||
int se, /* predictor estimate sample */
|
||||
int y, /* quantizer step size */
|
||||
int i, /* decoder input code */
|
||||
int sign,
|
||||
short *qtab)
|
||||
{
|
||||
unsigned char sp; /* u-law compressed 8-bit code */
|
||||
short dx; /* prediction error */
|
||||
char id; /* quantized prediction error */
|
||||
int sd; /* adjusted u-law decoded sample value */
|
||||
int im; /* biased magnitude of i */
|
||||
int imx; /* biased magnitude of id */
|
||||
|
||||
if (sr <= -32768)
|
||||
sr = 0;
|
||||
sp = linear2ulaw(sr << 2); /* short to u-law compression */
|
||||
dx = (ulaw2linear(sp) >> 2) - se; /* 16-bit prediction error */
|
||||
id = quantize(dx, y, qtab, sign - 1);
|
||||
if (id == i) {
|
||||
return (sp);
|
||||
} else {
|
||||
/* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */
|
||||
im = i ^ sign; /* 2's complement to biased unsigned */
|
||||
imx = id ^ sign;
|
||||
if (imx > im) { /* sp adjusted to next lower value */
|
||||
if (sp & 0x80)
|
||||
sd = (sp == 0xFF) ? 0x7E : sp + 1;
|
||||
else
|
||||
sd = (sp == 0) ? 0 : sp - 1;
|
||||
|
||||
} else { /* sp adjusted to next higher value */
|
||||
if (sp & 0x80)
|
||||
sd = (sp == 0x80) ? 0x80 : sp - 1;
|
||||
else
|
||||
sd = (sp == 0x7F) ? 0xFE : sp + 1;
|
||||
}
|
||||
return (sd);
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* From: https://dedected.org/trac/wiki/DSAA-Reversing
|
||||
*
|
||||
* FIXME: LICENSE? Copyrights?
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <libdect.h>
|
||||
|
||||
static const uint8_t sbox[256] = {
|
||||
176, 104, 111, 246, 125, 232, 22, 133,
|
||||
57, 124, 127, 222, 67, 240, 89, 169,
|
||||
251, 128, 50, 174, 95, 37, 140, 245,
|
||||
148, 107, 216, 234, 136, 152, 194, 41,
|
||||
207, 58, 80, 150, 28, 8, 149, 244,
|
||||
130, 55, 10, 86, 44, 255, 79, 196,
|
||||
96, 165, 131, 33, 48, 248, 243, 40,
|
||||
250, 147, 73, 52, 66, 120, 191, 252,
|
||||
97, 198, 241, 167, 26, 83, 3, 77,
|
||||
134, 211, 4, 135, 126, 143, 160, 183,
|
||||
49, 179, 231, 14, 47, 204, 105, 195,
|
||||
192, 217, 200, 19, 220, 139, 1, 82,
|
||||
193, 72, 239, 175, 115, 221, 92, 46,
|
||||
25, 145, 223, 34, 213, 61, 13, 163,
|
||||
88, 129, 62, 253, 98, 68, 36, 45,
|
||||
182, 141, 90, 5, 23, 190, 39, 84,
|
||||
93, 157, 214, 173, 108, 237, 100, 206,
|
||||
242, 114, 63, 212, 70, 164, 16, 162,
|
||||
59, 137, 151, 76, 110, 116, 153, 228,
|
||||
227, 187, 238, 112, 0, 189, 101, 32,
|
||||
15, 122, 233, 158, 155, 199, 181, 99,
|
||||
230, 170, 225, 138, 197, 7, 6, 30,
|
||||
94, 29, 53, 56, 119, 20, 17, 226,
|
||||
185, 132, 24, 159, 42, 203, 218, 247,
|
||||
166, 178, 102, 123, 177, 156, 109, 106,
|
||||
249, 254, 202, 201, 168, 65, 188, 121,
|
||||
219, 184, 103, 186, 172, 54, 171, 146,
|
||||
75, 215, 229, 154, 118, 205, 21, 31,
|
||||
78, 74, 87, 113, 27, 85, 9, 81,
|
||||
51, 12, 180, 142, 43, 224, 208, 91,
|
||||
71, 117, 69, 64, 2, 209, 60, 236,
|
||||
35, 235, 11, 210, 161, 144, 38, 18,
|
||||
};
|
||||
|
||||
static void bitperm(uint8_t start, uint8_t step, uint8_t * key)
|
||||
{
|
||||
static uint8_t copy[8];
|
||||
unsigned int i;
|
||||
|
||||
memcpy(copy, key, 8);
|
||||
memset(key, 0, 8);
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
key[start/8] |= ((copy[i / 8] & (1 << (i % 8))) >>
|
||||
(i % 8)) << (start % 8);
|
||||
start += step;
|
||||
start %= 64;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void bitperm1(uint8_t * key)
|
||||
{
|
||||
bitperm(46, 35, key);
|
||||
}
|
||||
|
||||
static void bitperm2(uint8_t * key)
|
||||
{
|
||||
bitperm(25, 47, key);
|
||||
}
|
||||
|
||||
static void bitperm3(uint8_t * key)
|
||||
{
|
||||
bitperm(60, 27, key);
|
||||
}
|
||||
|
||||
static void bitperm4(uint8_t * key)
|
||||
{
|
||||
bitperm(55, 39, key);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const uint8_t mix_factor[3][8] = {
|
||||
{2, 2, 2, 2, 3, 3, 3, 3},
|
||||
{2, 2, 3, 3, 2, 2, 3, 3},
|
||||
{2, 3, 2, 3, 2, 3, 2, 3},
|
||||
};
|
||||
|
||||
static const uint8_t mix_index[3][8] = {
|
||||
{4, 5, 6, 7, 0, 1, 2, 3},
|
||||
{2, 3, 0, 1, 6, 7, 4, 5},
|
||||
{1, 0, 3, 2, 5, 4, 7, 6},
|
||||
};
|
||||
|
||||
static void mix(uint8_t start, uint8_t alg, uint8_t * key)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t copy[8];
|
||||
|
||||
memcpy(copy, key, 8);
|
||||
for (i=0; i<8; i++)
|
||||
key[i] = copy[mix_index[alg][i]] + mix_factor[alg][i] * copy[i];
|
||||
}
|
||||
|
||||
static void mix1(uint8_t * key)
|
||||
{
|
||||
mix(4, 0, key);
|
||||
}
|
||||
|
||||
static void mix2(uint8_t * key)
|
||||
{
|
||||
mix(2, 1, key);
|
||||
}
|
||||
|
||||
static void mix3(uint8_t * key)
|
||||
{
|
||||
mix(1, 2, key);
|
||||
}
|
||||
|
||||
static void sub(uint8_t * s, uint8_t * t)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
s[i] = sbox[s[i] ^ t[i]];
|
||||
}
|
||||
|
||||
/* return in s */
|
||||
static void cassable(uint8_t start, uint8_t step, uint8_t * t, uint8_t * s)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0; i < 2; i++) {
|
||||
bitperm(start, step, t);
|
||||
sub(s, t);
|
||||
mix1(s);
|
||||
|
||||
bitperm(start, step, t);
|
||||
sub(s, t);
|
||||
mix2(s);
|
||||
|
||||
bitperm(start, step, t);
|
||||
sub(s, t);
|
||||
mix3(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* return in rand, modifies key */
|
||||
static void step1(uint8_t * rand, uint8_t * key)
|
||||
{
|
||||
|
||||
uint8_t tmp[8];
|
||||
|
||||
memcpy(tmp, rand, 8);
|
||||
|
||||
cassable(46, 35, tmp, key);
|
||||
cassable(25, 47, key, rand);
|
||||
|
||||
memcpy(key, rand, 8);
|
||||
}
|
||||
|
||||
static void step2(uint8_t * rand, uint8_t * key)
|
||||
{
|
||||
|
||||
uint8_t tmp[8];
|
||||
|
||||
memcpy(tmp, rand, 8);
|
||||
|
||||
cassable(60, 27, tmp, key);
|
||||
cassable(55, 39, key, rand);
|
||||
|
||||
memcpy(key, rand, 8);
|
||||
}
|
||||
|
||||
static void rev(uint8_t * v, uint8_t n)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t tmp;
|
||||
|
||||
for (i = 0; i < n / 2; i++) {
|
||||
tmp = v[i];
|
||||
v[i] = v[n - i - 1];
|
||||
v[n - i - 1] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void dsaa_main(uint8_t * rand, uint8_t * key, uint8_t * out);
|
||||
void dsaa_main(uint8_t * rand, uint8_t * key, uint8_t * out)
|
||||
{
|
||||
uint8_t a[8];
|
||||
uint8_t b[8];
|
||||
|
||||
rev(rand, 8);
|
||||
rev(key, 16);
|
||||
|
||||
step1(rand, key + 4);
|
||||
|
||||
memcpy(a, key + 4, 8);
|
||||
|
||||
memcpy(key + 4, key + 12, 4);
|
||||
memcpy(b, a, 8);
|
||||
step2(b, key);
|
||||
|
||||
rev(a, 8);
|
||||
rev(key, 8);
|
||||
|
||||
memcpy(out, key, 4);
|
||||
memcpy(out + 4, a, 8);
|
||||
memcpy(out + 12, key + 4, 4);
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* DECT Identities
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <identities.h>
|
||||
#include <utils.h>
|
||||
|
||||
|
||||
uint8_t dect_parse_ari(struct dect_ari *ari, uint64_t a)
|
||||
{
|
||||
ari->arc = (a & DECT_ARI_ARC_MASK) >> DECT_ARI_ARC_SHIFT;
|
||||
switch (ari->arc) {
|
||||
case DECT_ARC_A:
|
||||
ari->emc = (a & DECT_ARI_A_EMC_MASK) >> DECT_ARI_A_EMC_SHIFT;
|
||||
ari->fpn = (a & DECT_ARI_A_FPN_MASK) >> DECT_ARI_A_FPN_SHIFT;
|
||||
dect_debug("ARI class A: EMC: %.4x FPN: %.5x\n",
|
||||
ari->emc, ari->fpn);
|
||||
return DECT_ARC_A_LEN;
|
||||
case DECT_ARC_B:
|
||||
ari->eic = (a & DECT_ARI_B_EIC_MASK) >> DECT_ARI_B_EIC_SHIFT;
|
||||
ari->fpn = (a & DECT_ARI_B_FPN_MASK) >> DECT_ARI_B_FPN_SHIFT;
|
||||
ari->fps = (a & DECT_ARI_B_FPS_MASK) >> DECT_ARI_B_FPS_SHIFT;
|
||||
return DECT_ARC_B_LEN;
|
||||
case DECT_ARC_C:
|
||||
ari->poc = (a & DECT_ARI_C_POC_MASK) >> DECT_ARI_C_POC_SHIFT;
|
||||
ari->fpn = (a & DECT_ARI_C_FPN_MASK) >> DECT_ARI_C_FPN_SHIFT;
|
||||
ari->fps = (a & DECT_ARI_C_FPS_MASK) >> DECT_ARI_C_FPS_SHIFT;
|
||||
return DECT_ARC_C_LEN;
|
||||
case DECT_ARC_D:
|
||||
ari->gop = (a & DECT_ARI_D_GOP_MASK) >> DECT_ARI_D_GOP_SHIFT;
|
||||
ari->fpn = (a & DECT_ARI_D_FPN_MASK) >> DECT_ARI_D_FPN_SHIFT;
|
||||
return DECT_ARC_D_LEN;
|
||||
case DECT_ARC_E:
|
||||
ari->fil = (a & DECT_ARI_E_FIL_MASK) >> DECT_ARI_E_FIL_SHIFT;
|
||||
ari->fpn = (a & DECT_ARI_E_FPN_MASK) >> DECT_ARI_E_FPN_SHIFT;
|
||||
return DECT_ARC_E_LEN;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t dect_build_ari(const struct dect_ari *ari)
|
||||
{
|
||||
uint64_t a = 0;
|
||||
|
||||
a |= (uint64_t)ari->arc << DECT_ARI_ARC_SHIFT;
|
||||
switch (ari->arc) {
|
||||
case DECT_ARC_A:
|
||||
a |= (uint64_t)ari->emc << DECT_ARI_A_EMC_SHIFT;
|
||||
a |= (uint64_t)ari->fpn << DECT_ARI_A_FPN_SHIFT;
|
||||
break;
|
||||
case DECT_ARC_B:
|
||||
a |= (uint64_t)ari->eic << DECT_ARI_B_EIC_SHIFT;
|
||||
a |= (uint64_t)ari->fpn << DECT_ARI_B_FPN_SHIFT;
|
||||
a |= (uint64_t)ari->fps << DECT_ARI_B_FPS_SHIFT;
|
||||
break;
|
||||
case DECT_ARC_C:
|
||||
a |= (uint64_t)ari->poc << DECT_ARI_C_POC_SHIFT;
|
||||
a |= (uint64_t)ari->fpn << DECT_ARI_C_FPN_SHIFT;
|
||||
a |= (uint64_t)ari->fps << DECT_ARI_C_FPS_SHIFT;
|
||||
break;
|
||||
case DECT_ARC_D:
|
||||
a |= (uint64_t)ari->gop << DECT_ARI_D_GOP_SHIFT;
|
||||
a |= (uint64_t)ari->fpn << DECT_ARI_D_FPN_SHIFT;
|
||||
break;
|
||||
case DECT_ARC_E:
|
||||
a |= (uint64_t)ari->fil << DECT_ARI_E_FIL_SHIFT;
|
||||
a |= (uint64_t)ari->fpn << DECT_ARI_E_FPN_SHIFT;
|
||||
break;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
static bool dect_parse_ipei(struct dect_ipei *ipei, uint64_t i)
|
||||
{
|
||||
ipei->emc = (i & DECT_IPEI_EMC_MASK) >> DECT_IPEI_EMC_SHIFT;
|
||||
ipei->psn = (i & DECT_IPEI_PSN_MASK);
|
||||
dect_debug("IPEI: EMC: %.4x PSN: %.5x\n", ipei->emc, ipei->psn);
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint64_t dect_build_ipei(const struct dect_ipei *ipei)
|
||||
{
|
||||
uint64_t i = 0;
|
||||
|
||||
i |= (uint64_t)ipei->emc << DECT_IPEI_EMC_SHIFT;
|
||||
i |= (uint64_t)ipei->psn;
|
||||
return i;
|
||||
}
|
||||
|
||||
bool dect_parse_ipui(struct dect_ipui *ipui, const uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
tmp = __be64_to_cpu(*(__be64 *)&ptr[0]) >> 24;
|
||||
|
||||
ipui->put = ptr[0] & DECT_IPUI_PUT_MASK;
|
||||
switch (ipui->put) {
|
||||
case DECT_IPUI_N:
|
||||
if (len != 40)
|
||||
return false;
|
||||
return dect_parse_ipei(&ipui->pun.n.ipei, tmp);
|
||||
case DECT_IPUI_O:
|
||||
case DECT_IPUI_P:
|
||||
case DECT_IPUI_Q:
|
||||
case DECT_IPUI_R:
|
||||
case DECT_IPUI_S:
|
||||
case DECT_IPUI_T:
|
||||
case DECT_IPUI_U:
|
||||
default:
|
||||
dect_debug("IPUI: unhandled type %u\n", ipui->put);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t dect_build_ipui(uint8_t *ptr, const struct dect_ipui *ipui)
|
||||
{
|
||||
uint64_t tmp;
|
||||
|
||||
switch (ipui->put) {
|
||||
case DECT_IPUI_N:
|
||||
tmp = dect_build_ipei(&ipui->pun.n.ipei);
|
||||
break;
|
||||
case DECT_IPUI_O:
|
||||
case DECT_IPUI_P:
|
||||
case DECT_IPUI_Q:
|
||||
case DECT_IPUI_R:
|
||||
case DECT_IPUI_S:
|
||||
case DECT_IPUI_T:
|
||||
case DECT_IPUI_U:
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr[0] = ipui->put;
|
||||
ptr[0] |= (tmp >> 32) & ~DECT_IPUI_PUT_MASK;
|
||||
ptr[1] = tmp >> 24;
|
||||
ptr[2] = tmp >> 16;
|
||||
ptr[3] = tmp >> 8;
|
||||
ptr[4] = tmp >> 0;
|
||||
return 40;
|
||||
}
|
||||
|
||||
bool dect_ipui_cmp(const struct dect_ipui *i1, const struct dect_ipui *i2)
|
||||
{
|
||||
return memcmp(i1, i2, sizeof(*i1));
|
||||
}
|
||||
|
||||
void dect_default_individual_tpui(struct dect_tpui *tpui,
|
||||
const struct dect_ipui *ipui)
|
||||
{
|
||||
tpui->tpui = DECT_TPUI_DEFAULT_INDIVIDUAL_ID;
|
||||
|
||||
switch (ipui->put) {
|
||||
case DECT_IPUI_N:
|
||||
tpui->tpui |= ipui->pun.n.ipei.psn &
|
||||
DECT_TPUI_DEFAULT_INDIVIDUAL_IPUI_MASK;
|
||||
break;
|
||||
case DECT_IPUI_O:
|
||||
case DECT_IPUI_P:
|
||||
case DECT_IPUI_Q:
|
||||
case DECT_IPUI_R:
|
||||
case DECT_IPUI_S:
|
||||
case DECT_IPUI_T:
|
||||
case DECT_IPUI_U:
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* DECT Keypad Protocol helpers
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <libdect.h>
|
||||
#include <dect/keypad.h>
|
||||
#include <utils.h>
|
||||
|
||||
struct dect_keypad_buffer {
|
||||
struct dect_timer *timer;
|
||||
struct dect_ie_keypad keypad;
|
||||
uint8_t timeout;
|
||||
void *priv;
|
||||
void (*complete)(struct dect_handle *, void *,
|
||||
struct dect_ie_keypad *);
|
||||
};
|
||||
|
||||
static void dect_keypad_timer(struct dect_handle *dh, struct dect_timer *timer)
|
||||
{
|
||||
struct dect_keypad_buffer *kb = timer->data;
|
||||
|
||||
kb->complete(dh, kb->priv, &kb->keypad);
|
||||
}
|
||||
|
||||
void dect_keypad_append(struct dect_handle *dh, struct dect_keypad_buffer *kb,
|
||||
const struct dect_ie_keypad *keypad,
|
||||
bool sending_complete)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
if (keypad->len > 0)
|
||||
dect_stop_timer(dh, kb->timer);
|
||||
|
||||
len = sizeof(kb->keypad.info) - kb->keypad.len;
|
||||
len = min((unsigned int)keypad->len, len);
|
||||
memcpy(kb->keypad.info + kb->keypad.len, keypad->info, len);
|
||||
kb->keypad.len += len;
|
||||
|
||||
if (sending_complete || kb->keypad.len == sizeof(kb->keypad.info))
|
||||
kb->complete(dh, kb->priv, &kb->keypad);
|
||||
else if (keypad->len > 0)
|
||||
dect_start_timer(dh, kb->timer, kb->timeout);
|
||||
}
|
||||
|
||||
struct dect_keypad_buffer *
|
||||
dect_keypad_buffer_init(const struct dect_handle *dh, uint8_t timeout,
|
||||
void (*complete)(struct dect_handle *, void *priv,
|
||||
struct dect_ie_keypad *keypad),
|
||||
void *priv)
|
||||
{
|
||||
struct dect_keypad_buffer *kb;
|
||||
|
||||
kb = dect_zalloc(dh, sizeof(*kb));
|
||||
if (kb == NULL)
|
||||
goto err1;
|
||||
|
||||
kb->timer = dect_alloc_timer(dh);
|
||||
if (kb->timer == NULL)
|
||||
goto err2;
|
||||
kb->timer->callback = dect_keypad_timer;
|
||||
kb->timer->data = kb;
|
||||
|
||||
kb->complete = complete;
|
||||
kb->priv = priv;
|
||||
kb->timeout = timeout;
|
||||
return kb;
|
||||
|
||||
err1:
|
||||
dect_free(dh, kb);
|
||||
err2:
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,790 @@
|
|||
/*
|
||||
* DECT Link Control Entity (LCE)
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/byteorder/little_endian.h>
|
||||
#include <linux/dect.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <identities.h>
|
||||
#include <utils.h>
|
||||
#include <s_fmt.h>
|
||||
#include <b_fmt.h>
|
||||
#include <lce.h>
|
||||
#include <ss.h>
|
||||
|
||||
static const struct dect_sfmt_ie_desc lce_page_response_msg[] = {
|
||||
DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_NONE, IE_MANDATORY, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_NWK_ASSIGNED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_CIPHER_INFO, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE_END_MSG
|
||||
};
|
||||
|
||||
static const struct dect_sfmt_ie_desc lce_page_reject_msg[] = {
|
||||
DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_MANDATORY, IE_NONE, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_OPTIONAL, IE_NONE, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_REJECT_REASON, IE_OPTIONAL, IE_NONE, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_NONE, 0),
|
||||
DECT_SFMT_IE_END_MSG
|
||||
};
|
||||
|
||||
static const struct dect_nwk_protocol *protocols[DECT_S_PD_MAX + 1];
|
||||
|
||||
void dect_lce_register_protocol(const struct dect_nwk_protocol *protocol)
|
||||
{
|
||||
protocols[protocol->pd] = protocol;
|
||||
}
|
||||
|
||||
struct dect_msg_buf *dect_mbuf_alloc(const struct dect_handle *dh)
|
||||
{
|
||||
struct dect_msg_buf *mb;
|
||||
|
||||
mb = dect_malloc(dh, sizeof(*mb));
|
||||
if (mb == NULL)
|
||||
return NULL;
|
||||
memset(mb->head, 0, sizeof(mb->head));
|
||||
mb->data = mb->head;
|
||||
mb->len = 0;
|
||||
mb->type = 0;
|
||||
return mb;
|
||||
}
|
||||
|
||||
static ssize_t dect_mbuf_rcv(const struct dect_fd *dfd, struct dect_msg_buf *mb)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
memset(mb, 0, sizeof(*mb));
|
||||
mb->data = mb->head;
|
||||
len = recv(dfd->fd, mb->data, sizeof(mb->head), 0);
|
||||
if (len < 0)
|
||||
return len;
|
||||
mb->len = len;
|
||||
return len;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Location Table
|
||||
*/
|
||||
|
||||
static struct dect_lte *dect_lte_get_by_ipui(const struct dect_handle *dh,
|
||||
const struct dect_ipui *ipui)
|
||||
{
|
||||
struct dect_lte *lte;
|
||||
|
||||
list_for_each_entry(lte, &dh->ldb.entries, list) {
|
||||
if (!dect_ipui_cmp(<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);
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* libdect public API functions
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <netlink.h>
|
||||
#include <utils.h>
|
||||
#include <lce.h>
|
||||
|
||||
static void __fmtstring(1, 0) (*debug_hook)(const char *fmt, va_list ap);
|
||||
|
||||
void dect_set_debug_hook(void (*fn)(const char *fmt, va_list ap))
|
||||
{
|
||||
debug_hook = fn;
|
||||
}
|
||||
|
||||
void __fmtstring(1, 2) dect_debug(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (debug_hook != NULL)
|
||||
debug_hook(fmt, ap);
|
||||
else
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
struct dect_handle *dect_alloc_handle(struct dect_ops *ops)
|
||||
{
|
||||
struct dect_handle *dh;
|
||||
|
||||
if (ops->malloc == NULL)
|
||||
ops->malloc = malloc;
|
||||
if (ops->free == NULL)
|
||||
ops->free = free;
|
||||
|
||||
dh = ops->malloc(sizeof(*dh));
|
||||
if (dh == NULL)
|
||||
return NULL;
|
||||
dh->ops = ops;
|
||||
init_list_head(&dh->links);
|
||||
return dh;
|
||||
}
|
||||
|
||||
int dect_init(struct dect_handle *dh)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = dect_netlink_init(dh);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
|
||||
err = dect_lce_init(dh);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
dect_netlink_exit(dh);
|
||||
err1:
|
||||
return err;
|
||||
}
|
||||
|
||||
void dect_close_handle(struct dect_handle *dh)
|
||||
{
|
||||
dect_lce_exit(dh);
|
||||
dect_netlink_exit(dh);
|
||||
dect_free(dh, dh);
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* DECT Mobility Management (MM)
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/dect.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <utils.h>
|
||||
#include <s_fmt.h>
|
||||
#include <lce.h>
|
||||
#include <mm.h>
|
||||
|
||||
static const struct dect_sfmt_ie_desc mm_access_rights_request_msg_desc[] = {
|
||||
DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_NONE, IE_MANDATORY, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_AUTH_TYPE, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_CIPHER_INFO, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_SETUP_CAPABILITY, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_TERMINAL_CAPABILITY, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_MODEL_IDENTIFIER, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_CODEC_LIST, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE_END_MSG
|
||||
};
|
||||
|
||||
static const struct dect_sfmt_ie_desc mm_access_rights_reject_msg_desc[] = {
|
||||
DECT_SFMT_IE(S_VL_IE_REJECT_REASON, IE_OPTIONAL, IE_NONE, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_DURATION, IE_OPTIONAL, IE_NONE, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE_END_MSG
|
||||
};
|
||||
|
||||
#define mm_debug(fmt, args...) \
|
||||
dect_debug("MM: " fmt "\n", ## args)
|
||||
|
||||
int dect_mm_access_rights_req(struct dect_handle *dh,
|
||||
const struct dect_mm_access_rights_param *param)
|
||||
{
|
||||
static struct dect_transaction transaction;
|
||||
struct dect_ipui ipui;
|
||||
struct dect_mm_access_rights_request_msg msg = {
|
||||
.portable_identity = param->portable_identity,
|
||||
.auth_type = param->auth_type,
|
||||
.cipher_info = param->cipher_info,
|
||||
.setup_capability = NULL,
|
||||
//.terminal_capability = param->terminal_capability,
|
||||
.model_identifier = param->model_identifier,
|
||||
.codec_list = NULL,
|
||||
.escape_to_proprietary = NULL,
|
||||
};
|
||||
|
||||
mm_debug("access rights request");
|
||||
transaction.pd = DECT_S_PD_MM;
|
||||
|
||||
if (dect_open_transaction(dh, &transaction, &ipui) < 0)
|
||||
goto err1;
|
||||
|
||||
if (dect_lce_send(dh, &transaction, mm_access_rights_request_msg_desc,
|
||||
&msg.common, DECT_MM_ACCESS_RIGHTS_REQUEST,
|
||||
"MM-ACCESS_RIGHTS_REQUEST") < 0)
|
||||
goto err2;
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
dect_close_transaction(dh, &transaction);
|
||||
err1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void dect_mm_rcv_access_rights_reject(struct dect_handle *dh,
|
||||
struct dect_msg_buf *mb)
|
||||
{
|
||||
struct dect_mm_access_rights_reject_msg msg;
|
||||
|
||||
if (dect_parse_sfmt_msg(dh, mm_access_rights_reject_msg_desc, &msg.common, mb) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void dect_mm_rcv(struct dect_handle *dh, struct dect_transaction *ta,
|
||||
struct dect_msg_buf *mb)
|
||||
{
|
||||
mm_debug("receive msg type %x", mb->type);
|
||||
switch (mb->type) {
|
||||
case DECT_MM_AUTHENTICATION_REQUEST:
|
||||
case DECT_MM_AUTHENTICATION_REPLY:
|
||||
case DECT_MM_KEY_ALLOCATE:
|
||||
case DECT_MM_AUTHENTICATION_REJECT:
|
||||
case DECT_MM_ACCESS_RIGHTS_REQUEST:
|
||||
break;
|
||||
case DECT_MM_ACCESS_RIGHTS_ACCEPT:
|
||||
break;
|
||||
case DECT_MM_ACCESS_RIGHTS_REJECT:
|
||||
return dect_mm_rcv_access_rights_reject(dh, mb);
|
||||
case DECT_MM_ACCESS_RIGHTS_TERMINATE_REQUEST:
|
||||
case DECT_MM_ACCESS_RIGHTS_TERMINATE_ACCEPT:
|
||||
case DECT_MM_ACCESS_RIGHTS_TERMINATE_REJECT:
|
||||
case DECT_MM_CIPHER_REQUEST:
|
||||
case DECT_MM_CIPHER_SUGGEST:
|
||||
case DECT_MM_CIPHER_REJECT:
|
||||
case DECT_MM_INFO_REQUEST:
|
||||
case DECT_MM_INFO_ACCEPT:
|
||||
case DECT_MM_INFO_SUGGEST:
|
||||
case DECT_MM_INFO_REJECT:
|
||||
case DECT_MM_LOCATE_REQUEST:
|
||||
case DECT_MM_LOCATE_ACCEPT:
|
||||
case DECT_MM_DETACH:
|
||||
case DECT_MM_LOCATE_REJECT:
|
||||
case DECT_MM_IDENTITY_REQUEST:
|
||||
case DECT_MM_IDENTITY_REPLY:
|
||||
case DECT_MM_TEMPORARY_IDENTITY_ASSIGN:
|
||||
case DECT_MM_TEMPORARY_IDENTITY_ASSIGN_ACK:
|
||||
case DECT_MM_TEMPORARY_IDENTITY_ASSIGN_REJ:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dect_mm_open(struct dect_handle *dh,
|
||||
const struct dect_transaction *req,
|
||||
struct dect_msg_buf *mb)
|
||||
{
|
||||
dect_debug("MM: unknown transaction msg type: %x\n", mb->type);
|
||||
|
||||
switch (mb->type) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dect_nwk_protocol mm_protocol = {
|
||||
.name = "Mobility Management",
|
||||
.pd = DECT_S_PD_MM,
|
||||
.max_transactions = 1,
|
||||
.open = dect_mm_open,
|
||||
//.shutdown = dect_mm_shutdown,
|
||||
.rcv = dect_mm_rcv,
|
||||
};
|
||||
|
||||
static void __init dect_mm_init(void)
|
||||
{
|
||||
dect_lce_register_protocol(&mm_protocol);
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* DECT Netlink Interface
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/object.h>
|
||||
#include <netlink/msg.h>
|
||||
#include <netlink/dect/cluster.h>
|
||||
#include <netlink/dect/ari.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <netlink.h>
|
||||
#include <utils.h>
|
||||
|
||||
static void dect_netlink_event(struct dect_handle *dh, struct dect_fd *fd,
|
||||
uint32_t event)
|
||||
{
|
||||
nl_recvmsgs_default(dh->nlsock);
|
||||
}
|
||||
|
||||
static void dect_netlink_set_callback(struct dect_handle *dh,
|
||||
nl_recvmsg_msg_cb_t func,
|
||||
void *arg)
|
||||
{
|
||||
nl_socket_modify_cb(dh->nlsock, NL_CB_VALID, NL_CB_CUSTOM, func, arg);
|
||||
}
|
||||
|
||||
static void dect_netlink_parse_ari(struct dect_ari *ari, const struct nl_dect_ari *nlari)
|
||||
{
|
||||
ari->arc = nl_dect_ari_get_class(nlari);
|
||||
switch (ari->arc) {
|
||||
case DECT_ARC_A:
|
||||
ari->emc = nl_dect_ari_get_emc(nlari);
|
||||
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
||||
dect_debug("ARI class A: EMC: %.4x FPN: %.5x\n",
|
||||
ari->emc, ari->fpn);
|
||||
break;
|
||||
case DECT_ARC_B:
|
||||
ari->eic = nl_dect_ari_get_eic(nlari);
|
||||
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
||||
ari->fps = nl_dect_ari_get_fps(nlari);
|
||||
break;
|
||||
case DECT_ARC_C:
|
||||
ari->poc = nl_dect_ari_get_poc(nlari);
|
||||
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
||||
ari->fps = nl_dect_ari_get_fps(nlari);
|
||||
break;
|
||||
case DECT_ARC_D:
|
||||
ari->gop = nl_dect_ari_get_gop(nlari);
|
||||
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
||||
break;
|
||||
case DECT_ARC_E:
|
||||
ari->fil = nl_dect_ari_get_fil(nlari);
|
||||
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_cluster_cb(struct nl_object *obj, void *arg)
|
||||
{
|
||||
struct dect_handle *dh = arg;
|
||||
struct nl_dect_cluster *cl = (struct nl_dect_cluster *)obj;
|
||||
|
||||
dh->index = nl_dect_cluster_get_index(cl);
|
||||
dh->mode = nl_dect_cluster_get_mode(cl);
|
||||
dect_netlink_parse_ari(&dh->pari, nl_dect_cluster_get_pari(cl));
|
||||
}
|
||||
|
||||
static int dect_netlink_get_cluster_cb(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
return nl_msg_parse(msg, get_cluster_cb, arg);
|
||||
}
|
||||
|
||||
int dect_netlink_init(struct dect_handle *dh)
|
||||
{
|
||||
struct nl_dect_cluster *cl;
|
||||
int err;
|
||||
|
||||
dh->nlsock = nl_socket_alloc();
|
||||
if (dh->nlsock == NULL)
|
||||
goto err1;
|
||||
|
||||
err = nl_connect(dh->nlsock, NETLINK_DECT);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
err = nl_socket_set_nonblocking(dh->nlsock);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
dh->nlfd = dect_alloc_fd(dh);
|
||||
if (dh->nlfd == NULL)
|
||||
goto err2;
|
||||
dh->nlfd->fd = nl_socket_get_fd(dh->nlsock);
|
||||
|
||||
dh->nlfd->callback = dect_netlink_event;
|
||||
if (dect_register_fd(dh, dh->nlfd, DECT_FD_READ))
|
||||
goto err3;
|
||||
|
||||
cl = nl_dect_cluster_alloc();
|
||||
if (cl == NULL)
|
||||
goto err4;
|
||||
nl_dect_cluster_set_name(cl, "cluster0");
|
||||
|
||||
dect_netlink_set_callback(dh, dect_netlink_get_cluster_cb, dh);
|
||||
err = nl_dect_cluster_query(dh->nlsock, cl, 0);
|
||||
dect_netlink_set_callback(dh, NULL, NULL);
|
||||
if (err < 0)
|
||||
goto err5;
|
||||
|
||||
return 0;
|
||||
err5:
|
||||
nl_dect_cluster_put(cl);
|
||||
err4:
|
||||
dect_unregister_fd(dh, dh->nlfd);
|
||||
err3:
|
||||
dect_free(dh, dh->nlfd);
|
||||
err2:
|
||||
nl_close(dh->nlsock);
|
||||
err1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void dect_netlink_exit(struct dect_handle *dh)
|
||||
{
|
||||
dect_unregister_fd(dh, dh->nlfd);
|
||||
nl_close(dh->nlsock);
|
||||
dect_free(dh, dh->nlfd);
|
||||
}
|
|
@ -0,0 +1,991 @@
|
|||
/*
|
||||
* DECT S-Format messages
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <identities.h>
|
||||
#include <utils.h>
|
||||
#include <s_fmt.h>
|
||||
#include <lce.h>
|
||||
|
||||
static struct dect_ie_common *dect_ie_alloc(const struct dect_handle *dh,
|
||||
unsigned int size)
|
||||
{
|
||||
struct dect_ie_common *ie;
|
||||
|
||||
ie = dect_zalloc(dh, size);
|
||||
if (ie == NULL)
|
||||
return NULL;
|
||||
__dect_ie_init(ie);
|
||||
return ie;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_repeat_indicator(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_repeat_indicator *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
init_list_head(&dst->list);
|
||||
dst->type = src->data[0] & DECT_SFMT_IE_FIXED_VAL_MASK;
|
||||
switch (dst->type) {
|
||||
case DECT_SFMT_IE_LIST_NORMAL:
|
||||
case DECT_SFMT_IE_LIST_PRIORITIZED:
|
||||
return 0;
|
||||
default:
|
||||
dect_debug("invalid list type\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_repeat_indicator(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie)
|
||||
{
|
||||
struct dect_ie_repeat_indicator *src = dect_ie_container(src, ie);
|
||||
|
||||
dect_debug("build repeat indicator list %p %p\n", src->list.prev, src->list.next);
|
||||
dst->data[0] = src->type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_empty_single_octet(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_empty_single_octet(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie)
|
||||
{
|
||||
dst->data[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *call_classes[DECT_CALL_CLASS_MAX + 1] = {
|
||||
[DECT_CALL_CLASS_MESSAGE] = "message call",
|
||||
[DECT_CALL_CLASS_DECT_ISDN] = "DECT/ISDN IIP",
|
||||
[DECT_CALL_CLASS_NORMAL] = "normal call",
|
||||
[DECT_CALL_CLASS_INTERNAL] = "internal call",
|
||||
[DECT_CALL_CLASS_EMERGENCY] = "emergency call",
|
||||
[DECT_CALL_CLASS_SERVICE] = "service call",
|
||||
[DECT_CALL_CLASS_EXTERNAL_HO] = "external handover call",
|
||||
[DECT_CALL_CLASS_SUPPLEMENTARY_SERVICE] = "supplementary service call",
|
||||
[DECT_CALL_CLASS_QA_M] = "QA&M call",
|
||||
};
|
||||
|
||||
static const char *basic_services[DECT_SERVICE_MAX + 1] = {
|
||||
[DECT_SERVICE_BASIC_SPEECH_DEFAULT] = "basic speech default attributes",
|
||||
[DECT_SERVICE_DECT_GSM_IWP] = "DECT GSM IWP profile",
|
||||
[DECT_SERVICE_UMTS_IWP] = "DECT UMTS IWP",
|
||||
[DECT_SERVICE_LRMS] = "LRMS (E-profile) service",
|
||||
[DECT_SERVICE_GSM_IWP_SMS] = "GSM IWP SMS",
|
||||
[DECT_SERVICE_WIDEBAND_SPEECH] = "Wideband speech",
|
||||
[DECT_SERVICE_OTHER] = "Other",
|
||||
};
|
||||
|
||||
static void dect_sfmt_dump_basic_service(const struct dect_ie_common *_ie)
|
||||
{
|
||||
const struct dect_ie_basic_service *ie = dect_ie_container(ie, _ie);
|
||||
|
||||
dect_debug("basic service:\n\tcall class: %s\n\tservice: %s\n",
|
||||
call_classes[ie->class], basic_services[ie->service]);
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_basic_service(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_basic_service *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->class = src->data[1] >> DECT_BASIC_SERVICE_CALL_CLASS_SHIFT;
|
||||
dst->service = src->data[1] & DECT_BASIC_SERVICE_SERVICE_MASK;
|
||||
dect_sfmt_dump_basic_service(*ie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_basic_service(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie)
|
||||
{
|
||||
struct dect_ie_basic_service *src = dect_ie_container(src, ie);
|
||||
|
||||
dst->data[1] = src->class << DECT_BASIC_SERVICE_CALL_CLASS_SHIFT;
|
||||
dst->data[1] |= src->service;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_single_display(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_display *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->info[0] = src->data[1];
|
||||
dst->len = 1;
|
||||
dect_debug("single display: '%c'\n", dst->info[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_single_display(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *src)
|
||||
{
|
||||
struct dect_ie_display *ie = dect_ie_container(ie, src);
|
||||
|
||||
dst->data[1] = ie->info[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_single_keypad(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_keypad *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->info[0] = src->data[1];
|
||||
dst->len = 1;
|
||||
dect_debug("single keypad: '%c'\n", dst->info[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_release_reason(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_release_reason *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->reason = src->data[1];
|
||||
dect_debug("release reason: %x\n", dst->reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_release_reason(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie)
|
||||
{
|
||||
struct dect_ie_release_reason *src = dect_ie_container(src, ie);
|
||||
|
||||
dst->data[1] = src->reason;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_signal(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_signal *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->code = src->data[1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_signal(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *src)
|
||||
{
|
||||
struct dect_ie_signal *ie = dect_ie_container(ie, src);
|
||||
|
||||
dst->data[1] = ie->code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_timer_restart(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_timer_restart *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->code = src->data[1];
|
||||
switch (dst->code) {
|
||||
case DECT_TIMER_RESTART:
|
||||
case DECT_TIMER_STOP:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_portable_identity(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_portable_identity *dst = dect_ie_container(dst, *ie);
|
||||
uint8_t len;
|
||||
|
||||
if (src->len < S_VL_IE_PORTABLE_IDENTITY_MIN_SIZE)
|
||||
return -1;
|
||||
if (!(src->data[2] & 0x80))
|
||||
return -1;
|
||||
|
||||
dst->type = src->data[2] & S_VL_IE_PORTABLE_IDENTITY_TYPE_MASK;
|
||||
len = src->data[3] & S_VL_IE_PORTABLE_IDENTITY_LENGTH_MASK;
|
||||
|
||||
switch (dst->type) {
|
||||
case ID_TYPE_IPUI:
|
||||
if (!dect_parse_ipui(&dst->ipui, src->data + 4, len))
|
||||
dect_debug("parsing failed\n");
|
||||
return 0;
|
||||
case ID_TYPE_IPEI:
|
||||
return 0;
|
||||
case ID_TYPE_TPUI:
|
||||
return 0;
|
||||
default:
|
||||
dect_debug("invalid type %u\n", dst->type);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_portable_identity(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *src)
|
||||
{
|
||||
const struct dect_ie_portable_identity *ie = dect_ie_container(ie, src);
|
||||
uint8_t len;
|
||||
|
||||
switch (ie->type) {
|
||||
case ID_TYPE_IPUI:
|
||||
len = dect_build_ipui(&dst->data[4], &ie->ipui);
|
||||
if (len == 0)
|
||||
return -1;
|
||||
break;
|
||||
case ID_TYPE_IPEI:
|
||||
case ID_TYPE_TPUI:
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
dst->data[3] = 0x80 | len;
|
||||
dst->data[2] = 0x80 | ie->type;
|
||||
dst->len = 9;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_fixed_identity(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_fixed_identity *dst = dect_ie_container(dst, *ie);
|
||||
uint8_t len, ari_len;
|
||||
uint64_t ari;
|
||||
|
||||
if (src->len < S_VL_IE_FIXED_IDENTITY_MIN_SIZE)
|
||||
return -1;
|
||||
if (!(src->data[2] & 0x80))
|
||||
return -1;
|
||||
|
||||
dst->type = src->data[2] & S_VL_IE_FIXED_IDENTITY_TYPE_MASK;
|
||||
len = src->data[3] & S_VL_IE_FIXED_IDENTITY_LENGTH_MASK;
|
||||
|
||||
ari = __be64_to_cpu(*(__be64 *)&src->data[4]);
|
||||
ari_len = dect_parse_ari(&dst->ari, ari << 1);
|
||||
if (ari_len == 0)
|
||||
return -1;
|
||||
|
||||
switch (dst->type) {
|
||||
case ID_TYPE_ARI:
|
||||
case ID_TYPE_PARK:
|
||||
return ari_len + 1 == len;
|
||||
case ID_TYPE_ARI_RPN:
|
||||
case ID_TYPE_ARI_WRS:
|
||||
return 0;
|
||||
default:
|
||||
dect_debug("invalid type %u\n", dst->type);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_fixed_identity(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie)
|
||||
{
|
||||
struct dect_ie_fixed_identity *src = dect_ie_container(src, ie);
|
||||
uint64_t ari;
|
||||
|
||||
ari = dect_build_ari(&src->ari) >> 1;
|
||||
dst->data[8] = ari >> 24;
|
||||
dst->data[7] = ari >> 32;
|
||||
dst->data[6] = ari >> 40;
|
||||
dst->data[5] = ari >> 48;
|
||||
dst->data[4] = ari >> 56;
|
||||
dst->data[3] = 0x80 | (DECT_ARC_A_LEN + 1);
|
||||
dst->data[2] = 0x80 | src->type;
|
||||
dst->len = 9;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_progress_indicator(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_progress_indicator *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->location = src->data[2] & DECT_SFMT_IE_PROGRESS_INDICATOR_LOCATION_MASK;
|
||||
dst->progress = src->data[3];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_progress_indicator(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie)
|
||||
{
|
||||
struct dect_ie_progress_indicator *src = dect_ie_container(src, ie);
|
||||
|
||||
dst->data[3] = 0x80 | src->progress;
|
||||
dst->data[2] = 0x80 | src->location;
|
||||
dst->len = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_build_multi_display(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie)
|
||||
{
|
||||
struct dect_ie_display *src = dect_ie_container(src, ie);
|
||||
|
||||
memcpy(dst->data + 2, src->info, src->len);
|
||||
dst->len = src->len + 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_multi_keypad(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_keypad *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->len = src->len - 2;
|
||||
memcpy(dst->info, src->data + 2, src->len - 2);
|
||||
dect_debug("multi-keypad: '%.*s'\n", dst->len, dst->info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_reject_reason(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_reject_reason *dst = dect_ie_container(dst, *ie);
|
||||
|
||||
dst->reason = src->data[2];
|
||||
dect_debug("reject reason: %x\n", dst->reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_sfmt_parse_escape_to_proprietary(const struct dect_handle *dh,
|
||||
struct dect_ie_common **ie,
|
||||
const struct dect_sfmt_ie *src)
|
||||
{
|
||||
struct dect_ie_escape_to_proprietary *dst = dect_ie_container(dst, *ie);
|
||||
uint8_t dtype;
|
||||
|
||||
dtype = (src->data[2] & DECT_ESC_TO_PROPRIETARY_IE_DESC_TYPE_MASK);
|
||||
if (dtype != DECT_ESC_TO_PROPRIETARY_IE_DESC_EMC)
|
||||
return -1;
|
||||
dst->emc = __be16_to_cpu(*(__be16 *)&src->data[3]);
|
||||
dect_debug("EMC %x\n", dst->emc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dect_ie_handler {
|
||||
const char *name;
|
||||
size_t size;
|
||||
int (*parse)(const struct dect_handle *dh,
|
||||
struct dect_ie_common **dst,
|
||||
const struct dect_sfmt_ie *ie);
|
||||
int (*build)(struct dect_sfmt_ie *dst,
|
||||
const struct dect_ie_common *ie);
|
||||
} dect_ie_handlers[256] = {
|
||||
[S_SO_IE_REPEAT_INDICATOR] = {
|
||||
.name = "repeat indicator",
|
||||
.parse = dect_sfmt_parse_repeat_indicator,
|
||||
.build = dect_sfmt_build_repeat_indicator,
|
||||
},
|
||||
[S_SE_IE_SENDING_COMPLETE] = {
|
||||
.name = "sending complete",
|
||||
.size = sizeof(struct dect_ie_sending_complete),
|
||||
.parse = dect_sfmt_parse_empty_single_octet,
|
||||
.build = dect_sfmt_build_empty_single_octet,
|
||||
},
|
||||
[S_SE_IE_DELIMITER_REQUEST] = {
|
||||
.name = "delimiter request",
|
||||
.size = sizeof(struct dect_ie_delimiter_request),
|
||||
.parse = dect_sfmt_parse_empty_single_octet,
|
||||
.build = dect_sfmt_build_empty_single_octet,
|
||||
},
|
||||
[S_SE_IE_USE_TPUI] = {
|
||||
.name = "use TPUI",
|
||||
.size = sizeof(struct dect_ie_use_tpui),
|
||||
.parse = dect_sfmt_parse_empty_single_octet,
|
||||
.build = dect_sfmt_build_empty_single_octet,
|
||||
},
|
||||
[S_DO_IE_BASIC_SERVICE] = {
|
||||
.name = "basic service",
|
||||
.size = sizeof(struct dect_ie_basic_service),
|
||||
.parse = dect_sfmt_parse_basic_service,
|
||||
.build = dect_sfmt_build_basic_service,
|
||||
},
|
||||
[S_DO_IE_RELEASE_REASON] = {
|
||||
.name = "release reason",
|
||||
.size = sizeof(struct dect_ie_release_reason),
|
||||
.parse = dect_sfmt_parse_release_reason,
|
||||
.build = dect_sfmt_build_release_reason,
|
||||
},
|
||||
[S_DO_IE_SIGNAL] = {
|
||||
.name = "signal",
|
||||
.size = sizeof(struct dect_ie_signal),
|
||||
.parse = dect_sfmt_parse_signal,
|
||||
.build = dect_sfmt_build_signal,
|
||||
},
|
||||
[S_DO_IE_TIMER_RESTART] = {
|
||||
.name = "timer restart",
|
||||
.size = sizeof(struct dect_ie_timer_restart),
|
||||
.parse = dect_sfmt_parse_timer_restart,
|
||||
},
|
||||
[S_DO_IE_TEST_HOOK_CONTROL] = {
|
||||
.name = "test hook control",
|
||||
},
|
||||
[S_DO_IE_SINGLE_DISPLAY] = {
|
||||
.name = "single display",
|
||||
.size = sizeof(struct dect_ie_display),
|
||||
.parse = dect_sfmt_parse_single_display,
|
||||
.build = dect_sfmt_build_single_display,
|
||||
},
|
||||
[S_DO_IE_SINGLE_KEYPAD] = {
|
||||
.name = "single keypad",
|
||||
.size = sizeof(struct dect_ie_keypad),
|
||||
.parse = dect_sfmt_parse_single_keypad,
|
||||
},
|
||||
[S_VL_IE_INFO_TYPE] = {
|
||||
.name = "info type",
|
||||
.size = sizeof(struct dect_ie_info_type),
|
||||
},
|
||||
[S_VL_IE_IDENTITY_TYPE] = {
|
||||
.name = "identity type",
|
||||
.size = sizeof(struct dect_ie_identity_type)
|
||||
},
|
||||
[S_VL_IE_PORTABLE_IDENTITY] = {
|
||||
.name = "portable identity",
|
||||
.size = sizeof(struct dect_ie_portable_identity),
|
||||
.parse = dect_sfmt_parse_portable_identity,
|
||||
.build = dect_sfmt_build_portable_identity,
|
||||
},
|
||||
[S_VL_IE_FIXED_IDENTITY] = {
|
||||
.name = "fixed identity",
|
||||
.size = sizeof(struct dect_ie_fixed_identity),
|
||||
.parse = dect_sfmt_parse_fixed_identity,
|
||||
.build = dect_sfmt_build_fixed_identity,
|
||||
},
|
||||
[S_VL_IE_LOCATION_AREA] = {
|
||||
.name = "location area",
|
||||
.size = sizeof(struct dect_ie_location_area),
|
||||
},
|
||||
[S_VL_IE_NWK_ASSIGNED_IDENTITY] = {
|
||||
.name = "NWK assigned identity",
|
||||
.size = sizeof(struct dect_ie_nwk_assigned_identity),
|
||||
},
|
||||
[S_VL_IE_AUTH_TYPE] = {
|
||||
.name = "auth type",
|
||||
.size = sizeof(struct dect_ie_auth_type),
|
||||
},
|
||||
[S_VL_IE_ALLOCATION_TYPE] = {
|
||||
.name = "allocation type",
|
||||
.size = sizeof(struct dect_ie_allocation_type),
|
||||
},
|
||||
[S_VL_IE_RAND] = {
|
||||
.name = "RAND",
|
||||
.size = sizeof(struct dect_ie_rand),
|
||||
},
|
||||
[S_VL_IE_RES] = {
|
||||
.name = "RES",
|
||||
.size = sizeof(struct dect_ie_res),
|
||||
},
|
||||
[S_VL_IE_RS] = {
|
||||
.name = "RS",
|
||||
.size = sizeof(struct dect_ie_rs),
|
||||
},
|
||||
[S_VL_IE_IWU_ATTRIBUTES] = {
|
||||
.name = "IWU attributes",
|
||||
.size = sizeof(struct dect_ie_iwu_attributes),
|
||||
},
|
||||
[S_VL_IE_CALL_ATTRIBUTES] = {
|
||||
.name = "call attributes",
|
||||
.size = sizeof(struct dect_ie_call_attributes),
|
||||
},
|
||||
[S_VL_IE_SERVICE_CHANGE_INFO] = {
|
||||
.name = "service change info",
|
||||
.size = sizeof(struct dect_ie_service_change_info),
|
||||
},
|
||||
[S_VL_IE_CONNECTION_ATTRIBUTES] = {
|
||||
.name = "connection attributes",
|
||||
.size = sizeof(struct dect_ie_connection_attributes),
|
||||
},
|
||||
[S_VL_IE_CIPHER_INFO] = {
|
||||
.name = "cipher info",
|
||||
.size = sizeof(struct dect_ie_cipher_info),
|
||||
},
|
||||
[S_VL_IE_CALL_IDENTITY] = {
|
||||
.name = "call identity",
|
||||
.size = sizeof(struct dect_ie_call_identity),
|
||||
},
|
||||
[S_VL_IE_CONNECTION_IDENTITY] = {
|
||||
.name = "connection identity",
|
||||
.size = sizeof(struct dect_ie_connection_identity),
|
||||
},
|
||||
[S_VL_IE_FACILITY] = {
|
||||
.name = "facility",
|
||||
.size = sizeof(struct dect_ie_facility),
|
||||
},
|
||||
[S_VL_IE_PROGRESS_INDICATOR] = {
|
||||
.name = "progress indicator",
|
||||
.size = sizeof(struct dect_ie_progress_indicator),
|
||||
.parse = dect_sfmt_parse_progress_indicator,
|
||||
.build = dect_sfmt_build_progress_indicator,
|
||||
},
|
||||
[S_VL_IE_MMS_GENERIC_HEADER] = {
|
||||
.name = "MMS generic header",
|
||||
.size = sizeof(struct dect_ie_mms_generic_header),
|
||||
},
|
||||
[S_VL_IE_MMS_OBJECT_HEADER] = {
|
||||
.name = "MMS object header",
|
||||
.size = sizeof(struct dect_ie_mms_object_header),
|
||||
},
|
||||
[S_VL_IE_MMS_EXTENDED_HEADER] = {
|
||||
.name = "MMS extended header",
|
||||
.size = sizeof(struct dect_ie_mms_extended_header),
|
||||
},
|
||||
[S_VL_IE_TIME_DATE] = {
|
||||
.name = "time-date",
|
||||
.size = sizeof(struct dect_ie_time_date),
|
||||
},
|
||||
[S_VL_IE_MULTI_DISPLAY] = {
|
||||
.name = "multi display",
|
||||
.size = sizeof(struct dect_ie_display),
|
||||
.build = dect_sfmt_build_multi_display,
|
||||
},
|
||||
[S_VL_IE_MULTI_KEYPAD] = {
|
||||
.name = "multi keypad",
|
||||
.size = sizeof(struct dect_ie_keypad),
|
||||
.parse = dect_sfmt_parse_multi_keypad,
|
||||
},
|
||||
[S_VL_IE_FEATURE_ACTIVATE] = {
|
||||
.name = "feature activate",
|
||||
.size = sizeof(struct dect_ie_feature_activate),
|
||||
},
|
||||
[S_VL_IE_FEATURE_INDICATE] = {
|
||||
.name = "feature indicate",
|
||||
.size = sizeof(struct dect_ie_feature_indicate),
|
||||
},
|
||||
[S_VL_IE_NETWORK_PARAMETER] = {
|
||||
.name = "network parameter",
|
||||
.size = sizeof(struct dect_ie_network_parameter),
|
||||
},
|
||||
[S_VL_IE_EXT_HO_INDICATOR] = {
|
||||
.name = "ext H/O indicator",
|
||||
.size = sizeof(struct dect_ie_ext_ho_indicator),
|
||||
},
|
||||
[S_VL_IE_ZAP_FIELD] = {
|
||||
.name = "ZAP field",
|
||||
.size = sizeof(struct dect_ie_zap_field),
|
||||
},
|
||||
[S_VL_IE_SERVICE_CLASS] = {
|
||||
.name = "service class",
|
||||
.size = sizeof(struct dect_ie_service_class),
|
||||
},
|
||||
[S_VL_IE_KEY] = {
|
||||
.name = "key",
|
||||
.size = sizeof(struct dect_ie_key),
|
||||
},
|
||||
[S_VL_IE_REJECT_REASON] = {
|
||||
.name = "reject reason",
|
||||
.size = sizeof(struct dect_ie_reject_reason),
|
||||
.parse = dect_sfmt_parse_reject_reason,
|
||||
},
|
||||
[S_VL_IE_SETUP_CAPABILITY] = {
|
||||
.name = "setup capability",
|
||||
.size = sizeof(struct dect_ie_setup_capability),
|
||||
},
|
||||
[S_VL_IE_TERMINAL_CAPABILITY] = {
|
||||
.name = "terminal capability",
|
||||
.size = sizeof(struct dect_ie_terminal_capability),
|
||||
},
|
||||
[S_VL_IE_END_TO_END_COMPATIBILITY] = {
|
||||
.name = "end-to-end compatibility",
|
||||
.size = sizeof(struct dect_ie_end_to_end_compatibility),
|
||||
},
|
||||
[S_VL_IE_RATE_PARAMETERS] = {
|
||||
.name = "rate parameters",
|
||||
.size = sizeof(struct dect_ie_rate_parameters),
|
||||
},
|
||||
[S_VL_IE_TRANSIT_DELAY] = {
|
||||
.name = "transit delay",
|
||||
.size = sizeof(struct dect_ie_transit_delay),
|
||||
},
|
||||
[S_VL_IE_WINDOW_SIZE] = {
|
||||
.name = "window size",
|
||||
.size = sizeof(struct dect_ie_window_size),
|
||||
},
|
||||
[S_VL_IE_CALLING_PARTY_NUMBER] = {
|
||||
.name = "calling party number",
|
||||
.size = sizeof(struct dect_ie_calling_party_number),
|
||||
},
|
||||
[S_VL_IE_CALLING_PARTY_NAME] = {
|
||||
.name = "calling party name",
|
||||
.size = sizeof(struct dect_ie_calling_party_name),
|
||||
},
|
||||
[S_VL_IE_CALLED_PARTY_NUMBER] = {
|
||||
.name = "called party number",
|
||||
.size = sizeof(struct dect_ie_called_party_number),
|
||||
},
|
||||
[S_VL_IE_CALLED_PARTY_SUBADDR] = {
|
||||
.name = "called party subaddress",
|
||||
.size = sizeof(struct dect_ie_called_party_subaddress),
|
||||
},
|
||||
[S_VL_IE_DURATION] = {
|
||||
.name = "duration",
|
||||
.size = sizeof(struct dect_ie_duration),
|
||||
},
|
||||
[S_VL_IE_SEGMENTED_INFO] = {
|
||||
.name = "segmented info",
|
||||
.size = sizeof(struct dect_ie_segmented_info),
|
||||
},
|
||||
[S_VL_IE_ALPHANUMERIC] = {
|
||||
.name = "alphanumeric",
|
||||
.size = sizeof(struct dect_ie_alphanumeric),
|
||||
},
|
||||
[S_VL_IE_IWU_TO_IWU] = {
|
||||
.name = "IWU-to-IWU",
|
||||
.size = sizeof(struct dect_ie_iwu_to_iwu),
|
||||
},
|
||||
[S_VL_IE_MODEL_IDENTIFIER] = {
|
||||
.name = "model identifier",
|
||||
.size = sizeof(struct dect_ie_model_identifier),
|
||||
},
|
||||
[S_VL_IE_IWU_PACKET] = {
|
||||
.name = "IWU-packet",
|
||||
.size = sizeof(struct dect_ie_iwu_packet),
|
||||
},
|
||||
[S_VL_IE_ESCAPE_TO_PROPRIETARY] = {
|
||||
.name = "escape to proprietary",
|
||||
.size = sizeof(struct dect_ie_escape_to_proprietary),
|
||||
.parse = dect_sfmt_parse_escape_to_proprietary,
|
||||
},
|
||||
[S_VL_IE_CODEC_LIST] = {
|
||||
.name = "codec list",
|
||||
.size = sizeof(struct dect_ie_codec_list),
|
||||
},
|
||||
[S_VL_IE_EVENTS_NOTIFICATION] = {
|
||||
.name = "events notification",
|
||||
.size = sizeof(struct dect_ie_events_notification),
|
||||
},
|
||||
[S_VL_IE_CALL_INFORMATION] = {
|
||||
.name = "call information",
|
||||
.size = sizeof(struct dect_ie_call_information),
|
||||
},
|
||||
[S_VL_IE_ESCAPE_FOR_EXTENSION] = {
|
||||
.name = "escape for extension",
|
||||
},
|
||||
};
|
||||
|
||||
static struct dect_ie_common **
|
||||
dect_next_ie(const struct dect_sfmt_ie_desc *desc, struct dect_ie_common **ie)
|
||||
{
|
||||
if (desc->type == S_SO_IE_REPEAT_INDICATOR)
|
||||
return ((void *)ie) + sizeof(struct dect_ie_repeat_indicator);
|
||||
else if (!(desc->flags & DECT_SFMT_IE_REPEAT))
|
||||
return ie + 1;
|
||||
else
|
||||
return ie;
|
||||
}
|
||||
|
||||
static void dect_msg_ie_init(const struct dect_sfmt_ie_desc *desc,
|
||||
struct dect_ie_common **ie)
|
||||
{
|
||||
struct dect_ie_repeat_indicator *rep;
|
||||
|
||||
if (desc->flags & DECT_SFMT_IE_END)
|
||||
return;
|
||||
|
||||
//dect_debug("init message IE %p: <%s>\n",
|
||||
// ie, dect_ie_handlers[desc->type].name);
|
||||
|
||||
if (desc->type == S_SO_IE_REPEAT_INDICATOR) {
|
||||
rep = dect_ie_container(rep, (struct dect_ie_common *)ie);
|
||||
init_list_head(&rep->list);
|
||||
} else if (!(desc->flags & DECT_SFMT_IE_REPEAT))
|
||||
*ie = NULL;
|
||||
}
|
||||
|
||||
static int dect_parse_sfmt_ie_header(struct dect_sfmt_ie *ie,
|
||||
const struct dect_msg_buf *mb)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
if (mb->len < 1)
|
||||
return -1;
|
||||
|
||||
ie->id = mb->data[0] & DECT_SFMT_IE_FIXED_LEN;
|
||||
if (ie->id & DECT_SFMT_IE_FIXED_LEN) {
|
||||
ie->id |= (mb->data[0] & DECT_SFMT_IE_FIXED_ID_MASK);
|
||||
val = (mb->data[0] & DECT_SFMT_IE_FIXED_VAL_MASK);
|
||||
if (ie->id != S_SO_IE_DOUBLE_OCTET_ELEMENT) {
|
||||
ie->len = 1;
|
||||
if (ie->id == S_SO_IE_EXT_PREFIX)
|
||||
ie->id |= val;
|
||||
} else {
|
||||
if (mb->len < 2)
|
||||
return -1;
|
||||
ie->id |= val;
|
||||
ie->len = 2;
|
||||
}
|
||||
} else {
|
||||
if (mb->len < 2U || mb->len < 2U + mb->data[1])
|
||||
return -1;
|
||||
ie->id = mb->data[0];
|
||||
ie->len = mb->data[1] + 2;
|
||||
}
|
||||
ie->data = mb->data;
|
||||
|
||||
dect_debug("found IE: <%s> (%x) len: %u\n", dect_ie_handlers[ie->id].name,
|
||||
ie->id, ie->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_build_sfmt_ie_header(struct dect_sfmt_ie *dst, uint8_t id)
|
||||
{
|
||||
if (id & DECT_SFMT_IE_FIXED_LEN) {
|
||||
dst->data[0] |= id;
|
||||
if ((id & DECT_SFMT_IE_FIXED_ID_MASK) !=
|
||||
(S_SO_IE_DOUBLE_OCTET_ELEMENT & DECT_SFMT_IE_FIXED_ID_MASK))
|
||||
dst->len = 1;
|
||||
else
|
||||
dst->len = 2;
|
||||
} else {
|
||||
if (dst->len == 2)
|
||||
dst->len = 0;
|
||||
else {
|
||||
assert(dst->len > 2);
|
||||
dst->data[1] = dst->len - 2;
|
||||
dst->data[0] = id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dect_parse_sfmt_ie(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
struct dect_ie_common **dst,
|
||||
struct dect_sfmt_ie *ie)
|
||||
{
|
||||
const struct dect_ie_handler *ieh;
|
||||
int err = -1;
|
||||
|
||||
ieh = &dect_ie_handlers[ie->id];
|
||||
if (ieh->parse == NULL)
|
||||
goto err1;
|
||||
|
||||
if (ieh->size > 0) {
|
||||
*dst = dect_ie_alloc(dh, ieh->size);
|
||||
if (*dst == NULL)
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dect_debug("parse: IE <%s> dst %p len %u\n", ieh->name, *dst, ie->len);
|
||||
err = ieh->parse(dh, dst, ie);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
dect_free(dh, *dst);
|
||||
*dst = NULL;
|
||||
err1:
|
||||
dect_debug("smsg: IE parsing error\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
enum dect_sfmt_error dect_parse_sfmt_msg(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
struct dect_msg_common *_dst,
|
||||
struct dect_msg_buf *mb)
|
||||
{
|
||||
struct dect_ie_common **dst = &_dst->ie[0];
|
||||
struct dect_sfmt_ie _ie[2], *ie;
|
||||
uint8_t idx = 0;
|
||||
|
||||
dect_msg_ie_init(desc, dst);
|
||||
while (mb->len > 0) {
|
||||
/* Parse the next information element header */
|
||||
ie = &_ie[idx++ % array_size(_ie)];;
|
||||
if (dect_parse_sfmt_ie_header(ie, mb) < 0)
|
||||
return -1;
|
||||
|
||||
/* Treat empty variable length IEs as absent */
|
||||
if (!(ie->id & DECT_SFMT_IE_FIXED_LEN) && ie->len == 2)
|
||||
goto next;
|
||||
|
||||
/* Locate a matching member in the description and apply
|
||||
* policy checks. */
|
||||
while (1) {
|
||||
if (desc->flags & DECT_SFMT_IE_END)
|
||||
goto out;
|
||||
|
||||
switch (desc->f_p) {
|
||||
case DECT_SFMT_IE_MANDATORY:
|
||||
if (desc->type == ie->id)
|
||||
goto found;
|
||||
return DECT_SFMT_MANDATORY_IE_MISSING;
|
||||
case DECT_SFMT_IE_NONE:
|
||||
if (desc->type == ie->id)
|
||||
return -1;
|
||||
break;
|
||||
case DECT_SFMT_IE_OPTIONAL:
|
||||
if (desc->type == ie->id)
|
||||
goto found;
|
||||
if (desc->type == S_DO_IE_SINGLE_DISPLAY &&
|
||||
ie->id == S_VL_IE_MULTI_DISPLAY)
|
||||
goto found;
|
||||
if (desc->type == S_DO_IE_SINGLE_KEYPAD &&
|
||||
ie->id == S_VL_IE_MULTI_KEYPAD)
|
||||
goto found;
|
||||
break;
|
||||
}
|
||||
|
||||
dst = dect_next_ie(desc, dst);
|
||||
desc++;
|
||||
dect_msg_ie_init(desc, dst);
|
||||
}
|
||||
found:
|
||||
/* Ignore corrupt optional IEs */
|
||||
if (dect_parse_sfmt_ie(dh, desc, dst, ie) < 0 &&
|
||||
desc->f_p == DECT_SFMT_IE_MANDATORY)
|
||||
return DECT_SFMT_MANDATORY_IE_ERROR;
|
||||
|
||||
next:
|
||||
dect_mbuf_pull(mb, ie->len);
|
||||
|
||||
dst = dect_next_ie(desc, dst);
|
||||
desc++;
|
||||
dect_msg_ie_init(desc, dst);
|
||||
}
|
||||
out:
|
||||
while (!(desc->flags & DECT_SFMT_IE_END)) {
|
||||
dect_debug("clear missing IE: <%s>\n", dect_ie_handlers[desc->type].name);
|
||||
if (desc->f_p == DECT_SFMT_IE_MANDATORY)
|
||||
return DECT_SFMT_MANDATORY_IE_MISSING;
|
||||
dst = dect_next_ie(desc, dst);
|
||||
desc++;
|
||||
dect_msg_ie_init(desc, dst);
|
||||
}
|
||||
|
||||
return DECT_SFMT_OK;
|
||||
}
|
||||
|
||||
static enum dect_sfmt_error
|
||||
dect_build_sfmt_ie(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
struct dect_msg_buf *mb,
|
||||
struct dect_ie_common *ie)
|
||||
{
|
||||
const struct dect_ie_handler *ieh;
|
||||
uint16_t type = desc->type;
|
||||
struct dect_sfmt_ie dst;
|
||||
enum dect_sfmt_error err = 0;
|
||||
|
||||
if (desc->p_f == DECT_SFMT_IE_NONE)
|
||||
return DECT_SFMT_INVALID_IE;
|
||||
|
||||
if (type == S_DO_IE_SINGLE_DISPLAY) {
|
||||
struct dect_ie_display *display = dect_ie_container(display, ie);
|
||||
if (display->len > 1)
|
||||
type = S_VL_IE_MULTI_DISPLAY;
|
||||
}
|
||||
if (type == S_DO_IE_SINGLE_KEYPAD) {
|
||||
struct dect_ie_keypad *keypad = dect_ie_container(keypad, ie);
|
||||
if (keypad->len > 1)
|
||||
type = S_VL_IE_MULTI_KEYPAD;
|
||||
}
|
||||
|
||||
ieh = &dect_ie_handlers[type];
|
||||
if (ieh->build == NULL)
|
||||
goto err1;
|
||||
|
||||
dect_debug("build IE: %s %p\n", ieh->name, ie);
|
||||
dst.data = mb->data + mb->len;
|
||||
dst.len = 0;
|
||||
err = ieh->build(&dst, ie);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
|
||||
dect_build_sfmt_ie_header(&dst, type);
|
||||
mb->len += dst.len;
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
return err;
|
||||
}
|
||||
|
||||
enum dect_sfmt_error dect_build_sfmt_msg(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
const struct dect_msg_common *_src,
|
||||
struct dect_msg_buf *mb)
|
||||
{
|
||||
struct dect_ie_common * const *src = &_src->ie[0], **next, *rsrc;
|
||||
struct dect_ie_repeat_indicator *rep;
|
||||
enum dect_sfmt_error err;
|
||||
|
||||
while (!(desc->flags & DECT_SFMT_IE_END)) {
|
||||
next = dect_next_ie(desc, (struct dect_ie_common **)src);
|
||||
|
||||
if (desc->type == S_SO_IE_REPEAT_INDICATOR) {
|
||||
rep = (struct dect_ie_repeat_indicator *)src;
|
||||
if (rep->list.next == NULL || list_empty(&rep->list)) {
|
||||
desc++;
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (rep->list.next->next != &rep->list)
|
||||
err = dect_build_sfmt_ie(dh, desc, mb, &rep->common);
|
||||
desc++;
|
||||
|
||||
assert(desc->flags & DECT_SFMT_IE_REPEAT);
|
||||
assert(!list_empty(&rep->list));
|
||||
list_for_each_entry(rsrc, &rep->list, list) {
|
||||
dect_debug("list elem %p next %p\n", rsrc, rsrc->list.next);
|
||||
err = dect_build_sfmt_ie(dh, desc, mb, rsrc);
|
||||
}
|
||||
} else {
|
||||
if (*src == NULL)
|
||||
goto next;
|
||||
err = dect_build_sfmt_ie(dh, desc, mb, *src);
|
||||
}
|
||||
next:
|
||||
src = next;
|
||||
desc++;
|
||||
}
|
||||
|
||||
return DECT_SFMT_OK;
|
||||
}
|
||||
|
||||
void dect_msg_free(const struct dect_handle *dh,
|
||||
const struct dect_sfmt_ie_desc *desc,
|
||||
struct dect_msg_common *msg)
|
||||
{
|
||||
struct dect_ie_common **ie = &msg->ie[0], **next;
|
||||
|
||||
while (!(desc->flags & DECT_SFMT_IE_END)) {
|
||||
next = dect_next_ie(desc, ie);
|
||||
|
||||
//dect_debug("free %s %p\n", dect_ie_handlers[desc->type].name, ie);
|
||||
if (desc->type == S_SO_IE_REPEAT_INDICATOR)
|
||||
desc++;
|
||||
else if (*ie != NULL && --(*ie)->refcnt == 0)
|
||||
dect_free(dh, *ie);
|
||||
|
||||
ie = next;
|
||||
desc++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* DECT Supplementary Services (SS)
|
||||
*
|
||||
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/dect.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <utils.h>
|
||||
#include <s_fmt.h>
|
||||
#include <lce.h>
|
||||
#include <ss.h>
|
||||
|
||||
|
||||
static const struct dect_sfmt_ie_desc ciss_facility_msg_desc[] = {
|
||||
DECT_SFMT_IE(S_VL_IE_FACILITY, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
|
||||
DECT_SFMT_IE(S_DO_IE_SINGLE_DISPLAY, IE_OPTIONAL, IE_NONE, 0),
|
||||
DECT_SFMT_IE(S_DO_IE_SINGLE_KEYPAD, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_FEATURE_ACTIVATE, IE_NONE, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_FEATURE_INDICATE, IE_OPTIONAL, IE_NONE, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_IWU_TO_IWU, IE_OPTIONAL, IE_OPTIONAL, DECT_SFMT_IE_REPEAT),
|
||||
DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_TIME_DATE, IE_OPTIONAL, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_EVENTS_NOTIFICATION, IE_OPTIONAL, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE(S_VL_IE_CALL_INFORMATION, IE_OPTIONAL, IE_OPTIONAL, 0),
|
||||
DECT_SFMT_IE_END_MSG
|
||||
};
|
||||
|
||||
void dect_clss_rcv(struct dect_handle *dh, struct dect_msg_buf *mb)
|
||||
{
|
||||
struct dect_ciss_facility_msg msg;
|
||||
|
||||
if (mb->type != CISS_FACILITY)
|
||||
return;
|
||||
|
||||
if (dect_parse_sfmt_msg(dh, ciss_facility_msg_desc, &msg.common, mb) < 0)
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <libdect.h>
|
||||
#include <utils.h>
|
||||
|
||||
#ifndef SOCK_NONBLOCK
|
||||
#define SOCK_NONBLOCK O_NONBLOCK
|
||||
#endif
|
||||
|
||||
void dect_hexdump(const char *prefix, const uint8_t *buf, size_t size)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (i % 16 == 0)
|
||||
dect_debug("%s%s: ", i ? "\n" : "", prefix);
|
||||
dect_debug("%.2x ", buf[i]);
|
||||
}
|
||||
dect_debug("\n\n");
|
||||
}
|
||||
|
||||
void *dect_malloc(const struct dect_handle *dh, size_t size)
|
||||
{
|
||||
return dh->ops->malloc(size);
|
||||
}
|
||||
|
||||
void *dect_zalloc(const struct dect_handle *dh, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = dect_malloc(dh, size);
|
||||
if (ptr != NULL)
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void dect_free(const struct dect_handle *dh, void *ptr)
|
||||
{
|
||||
dh->ops->free(ptr);
|
||||
}
|
||||
|
||||
struct dect_timer *dect_alloc_timer(const struct dect_handle *dh)
|
||||
{
|
||||
return dect_malloc(dh, sizeof(struct dect_timer) +
|
||||
dh->ops->event_ops->timer_priv_size);
|
||||
}
|
||||
|
||||
void dect_start_timer(const struct dect_handle *dh,
|
||||
struct dect_timer *timer, unsigned int timeout)
|
||||
{
|
||||
struct timeval tv = {
|
||||
.tv_sec = timeout,
|
||||
};
|
||||
|
||||
dh->ops->event_ops->start_timer(dh, timer, &tv);
|
||||
}
|
||||
|
||||
void dect_stop_timer(const struct dect_handle *dh, struct dect_timer *timer)
|
||||
{
|
||||
dh->ops->event_ops->stop_timer(dh, timer);
|
||||
}
|
||||
|
||||
struct dect_fd *dect_alloc_fd(const struct dect_handle *dh)
|
||||
{
|
||||
struct dect_fd *dfd;
|
||||
|
||||
dfd = dect_malloc(dh, sizeof(struct dect_fd) +
|
||||
dh->ops->event_ops->fd_priv_size);
|
||||
if (dfd == NULL)
|
||||
return NULL;
|
||||
dfd->fd = -1;
|
||||
return dfd;
|
||||
}
|
||||
|
||||
int dect_register_fd(const struct dect_handle *dh, struct dect_fd *dfd,
|
||||
uint32_t events)
|
||||
{
|
||||
return dh->ops->event_ops->register_fd(dh, dfd, events);
|
||||
}
|
||||
|
||||
void dect_unregister_fd(const struct dect_handle *dh, struct dect_fd *dfd)
|
||||
{
|
||||
dh->ops->event_ops->unregister_fd(dh, dfd);
|
||||
}
|
||||
|
||||
void dect_close(const struct dect_handle *dh, struct dect_fd *dfd)
|
||||
{
|
||||
if (dfd->fd >= 0)
|
||||
close(dfd->fd);
|
||||
dect_free(dh, dfd);
|
||||
}
|
||||
|
||||
struct dect_fd *dect_socket(const struct dect_handle *dh, int type, int protocol)
|
||||
{
|
||||
struct dect_fd *dfd;
|
||||
|
||||
dfd = dect_alloc_fd(dh);
|
||||
if (dfd == NULL)
|
||||
goto err1;
|
||||
|
||||
dfd->fd = socket(AF_DECT, type | SOCK_NONBLOCK, protocol);
|
||||
if (dfd->fd < 0)
|
||||
goto err2;
|
||||
|
||||
return dfd;
|
||||
|
||||
err2:
|
||||
dect_close(dh, dfd);
|
||||
err1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dect_fd *dect_accept(const struct dect_handle *dh,
|
||||
const struct dect_fd *dfd,
|
||||
struct sockaddr *addr, socklen_t len)
|
||||
{
|
||||
struct dect_fd *nfd;
|
||||
|
||||
nfd = dect_alloc_fd(dh);
|
||||
if (nfd == NULL)
|
||||
goto err1;
|
||||
|
||||
nfd->fd = accept(dfd->fd, addr, &len);
|
||||
if (nfd->fd < 0)
|
||||
goto err2;
|
||||
if (fcntl(nfd->fd, F_SETFL, O_NONBLOCK) < 0)
|
||||
goto err2;
|
||||
|
||||
return nfd;
|
||||
|
||||
err2:
|
||||
dect_close(dh, nfd);
|
||||
err1:
|
||||
return NULL;
|
||||
}
|
Reference in New Issue