dect
/
libdect
Archived
13
0
Fork 0

Import libdect

Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
Patrick McHardy 2009-05-06 18:41:57 +02:00
commit 0406a88b39
62 changed files with 12248 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@ -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

42
Makefile.defs.in Normal file
View File

@ -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

5
Makefile.in Normal file
View File

@ -0,0 +1,5 @@
SUBDIRS += include
SUBDIRS += src
SUBDIRS += example
include Makefile.rules

108
Makefile.rules.in Normal file
View File

@ -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="$@/"

4
autogen.sh Executable file
View File

@ -0,0 +1,4 @@
#! /bin/sh
autoreconf -fi;
rm -Rf autom4te*.cache config.h.in~

74
configure.ac Normal file
View File

@ -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

1417
doc/Doxyfile.in Normal file

File diff suppressed because it is too large Load Diff

4
doc/Makefile.in Normal file
View File

@ -0,0 +1,4 @@
all: doxygen
doxygen:
$(DOXYGEN) $(SUBDIR)Doxyfile

1
example/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
test

8
example/Makefile.in Normal file
View File

@ -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

95
example/audio.c Normal file
View File

@ -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);
}
}

23
example/common.h Normal file
View File

@ -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 */

115
example/event_ops.c Normal file
View File

@ -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);
}

BIN
example/mm Executable file

Binary file not shown.

74
example/mm.c Normal file
View File

@ -0,0 +1,74 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dect/libdect.h>
#include "common.h"
enum phones { PHONE1, PHONE2, PHONE3, };
static const struct dect_ipui ipuis[] = {
[PHONE1] = {
.put = DECT_IPUI_N,
.pun.n.ipei = {
.emc = 0x08ae,
.psn = 0x83d1e,
},
},
[PHONE2] = {
.put = DECT_IPUI_N,
.pun.n.ipei = {
.emc = 0x08ae,
.psn = 0x8969f,
},
},
[PHONE3] = {
.put = DECT_IPUI_N,
.pun.n.ipei = {
.emc = 0x08ae,
.psn = 0x5b9a0,
},
},
};
static const struct dect_mm_ops mm_ops = {
.mm_access_rights_ind = 0,
.mm_access_rights_cfm = 0,
};
static int mm_access_rights_request(struct dect_handle *dh)
{
struct dect_ie_portable_identity portable_identity;
struct dect_mm_access_rights_param param = {
.portable_identity = &portable_identity,
};
dect_ie_init(&portable_identity);
portable_identity.type = ID_TYPE_IPUI;
portable_identity.ipui = ipuis[PHONE1];
return dect_mm_access_rights_req(dh, &param);
}
static struct dect_ops ops = {
.mm_ops = &mm_ops,
};
int main(int argc, char **argv)
{
if (dect_event_ops_init(&ops) < 0)
exit(1);
dh = dect_alloc_handle(&ops);
if (dh == NULL)
exit(1);
if (dect_init(dh) < 0)
exit(1);
if (mm_access_rights_request(dh) < 0)
exit(1);
dect_event_loop();
dect_close_handle(dh);
dect_event_ops_cleanup();
return 0;
}

294
example/test.c Normal file
View File

@ -0,0 +1,294 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/time.h>
#include <event.h>
#include <dect/libdect.h>
#include <dect/terminal.h>
#include <dect/keypad.h>
#include "common.h"
struct call {
struct dect_keypad_buffer *keybuf;
struct dect_audio_handle *audio;
struct event event;
enum {
BLINK0,
RING,
BLINK1,
SCROLLING,
} state;
uint8_t scroll_off;
uint8_t ring_pattern;
};
enum phones { PHONE1, PHONE2, PHONE3, };
static const struct dect_ipui ipuis[] = {
[PHONE1] = {
.put = DECT_IPUI_N,
.pun.n.ipei = {
.emc = 0x08ae,
.psn = 0x83d1e,
},
},
[PHONE2] = {
.put = DECT_IPUI_N,
.pun.n.ipei = {
.emc = 0x08ae,
.psn = 0x8969f,
},
},
[PHONE3] = {
.put = DECT_IPUI_N,
.pun.n.ipei = {
.emc = 0x08ae,
.psn = 0x5b9a0,
},
},
};
static void dect_mncc_timer(int fd, short even, void *data);
static void dect_mncc_timer_schedule(struct dect_call *call)
{
struct call *priv = dect_call_priv(call);
struct timeval tv = { .tv_sec = 1 };
evtimer_set(&priv->event, dect_mncc_timer, call);
evtimer_add(&priv->event, &tv);
}
static void dect_mncc_timer(int fd, short even, void *data)
{
struct dect_call *call = data;
struct dect_ie_display display;
struct dect_ie_signal signal;
struct dect_mncc_info_param info = {
//.signal = &signal,
.display = &display,
};
static int code;
init_list_head(&info.progress_indicator.list);
dect_ie_init(&signal);
signal.code = DECT_SIGNAL_ALERTING_BASE | (code % 10);
dect_display_init(&display);
dect_display_append_char(&display, code++);
dect_mncc_info_req(dh, call, &info);
dect_mncc_timer_schedule(call);
}
static void dect_keypad_complete(struct dect_handle *dh, void *call,
struct dect_ie_keypad *keypad)
{
printf("keypad complete: '%.*s'\n", keypad->len, keypad->info);
}
static void dect_mncc_connect_ind(struct dect_handle *dh, struct dect_call *call,
const struct dect_mncc_connect_param *param)
{
printf("MNCC_CONNECT-ind\n");
}
static void dect_mncc_setup_ind(struct dect_handle *dh, struct dect_call *call,
const struct dect_mncc_setup_param *setup)
{
struct call *priv = dect_call_priv(call);
struct dect_ie_signal signal;
struct dect_mncc_connect_param connect = {
//.signal = &signal,
};
printf("MNCC_SETUP-ind\n");
dect_ie_init(&signal);
signal.code = DECT_SIGNAL_DIAL_TONE_ON;
priv->keybuf = dect_keypad_buffer_init(dh, 3, dect_keypad_complete, call);
priv->audio = dect_audio_open();
dect_mncc_connect_req(dh, call, &connect);
}
static void dect_mncc_setup_ack_ind(struct dect_handle *dh, struct dect_call *call,
const struct dect_mncc_setup_ack_param *param)
{
printf("MNCC_SETUP_ACK-ind\n");
}
static void dect_mncc_info_ind(struct dect_handle *dh, struct dect_call *call,
const struct dect_mncc_info_param *param)
{
struct call *priv = dect_call_priv(call);
struct dect_ie_progress_indicator progress_indicator;
struct dect_ie_signal signal;
struct dect_mncc_info_param info = {
.signal = &signal,
};
printf("MNCC_INFO-ind\n");
return;
dect_keypad_append(dh, priv->keybuf, param->keypad,
param->sending_complete);
dect_ie_init(&signal);
signal.code = DECT_SIGNAL_DIAL_TONE_ON;
dect_ie_init(&progress_indicator);
progress_indicator.location = DECT_LOCATION_PRIVATE_NETWORK_SERVING_LOCAL_USER;
progress_indicator.progress = DECT_PROGRESS_INBAND_INFORMATION_NOW_AVAILABLE;
init_list_head(&info.progress_indicator.list);
list_add_tail(&progress_indicator.common.list, &info.progress_indicator.list);
dect_mncc_info_req(dh, call, &info);
}
static void dect_mncc_send_call_info(struct dect_call *call)
{
struct call *priv = dect_call_priv(call);
struct dect_ie_display display;
struct dect_ie_signal signal;
struct dect_mncc_info_param info = {
.display = &display,
.signal = &signal,
};
static const char *text = " kaber ";
dect_display_init(&display);
dect_display_append_char(&display, DECT_C_CLEAR_DISPLAY);
dect_display_append_char(&display, '*');
dect_display_append(&display, text + priv->scroll_off,
strlen(text) - priv->scroll_off);
dect_display_append(&display, text, priv->scroll_off);
dect_display_append_char(&display, '*');
dect_ie_init(&signal);
if (priv->state == RING) {
signal.code = DECT_SIGNAL_ALERTING_BASE | priv->ring_pattern;
priv->ring_pattern = (priv->ring_pattern + 1) % 8;
} else
signal.code = DECT_SIGNAL_ALERTING_BASE | DECT_RING_OFF;
if (priv->state != SCROLLING)
priv->state++;
else {
priv->scroll_off = (priv->scroll_off + 1) % (strlen(text) + 1);
if (priv->scroll_off == 0)
priv->state = 0;
}
dect_mncc_info_req(dh, call, &info);
}
static void dect_mncc_info_timer(int fd, short even, void *data);
static void dect_mncc_info_timer_schedule(struct dect_call *call)
{
struct call *priv = dect_call_priv(call);
struct timeval tv = { .tv_usec = 500000 };
evtimer_set(&priv->event, dect_mncc_info_timer, call);
evtimer_add(&priv->event, &tv);
}
static void dect_mncc_info_timer(int fd, short even, void *data)
{
struct dect_call *call = data;
dect_mncc_send_call_info(call);
dect_mncc_info_timer_schedule(call);
}
static void dect_mncc_alert_ind(struct dect_handle *dh, struct dect_call *call,
const struct dect_mncc_alert_param *param)
{
printf("MNCC_ALERT-ind\n");
dect_mncc_info_timer(0, 0, call);
}
static void dect_mncc_reject_ind(struct dect_handle *dh, struct dect_call *call,
const struct dect_mncc_release_param *param)
{
struct call *priv = dect_call_priv(call);
printf("MNCC_REJECT-ind\n");
event_del(&priv->event);
}
static void dect_open_call(struct dect_handle *dh, const struct dect_ipui *ipui)
{
struct dect_ie_basic_service basic_service;
struct dect_mncc_setup_param param = {
.basic_service = &basic_service,
};
struct dect_call *call;
struct call *priv;
call = dect_call_alloc(dh);
if (call == NULL)
return;
priv = dect_call_priv(call);
dect_ie_init(&basic_service);
basic_service.class = DECT_CALL_CLASS_NORMAL;
basic_service.service = DECT_SERVICE_BASIC_SPEECH_DEFAULT;
dect_mncc_setup_req(dh, call, ipui, &param);
}
static void dect_dl_u_data_ind(struct dect_handle *dh, struct dect_call *call,
struct dect_msg_buf *mb)
{
struct call *priv = dect_call_priv(call);
dect_dl_u_data_req(dh, call, mb);
dect_audio_queue(priv->audio, mb);
}
static const struct dect_cc_ops cc_ops = {
.priv_size = sizeof(struct call),
.mncc_connect_ind = dect_mncc_connect_ind,
.mncc_setup_ind = dect_mncc_setup_ind,
.mncc_setup_ack_ind = dect_mncc_setup_ack_ind,
.mncc_info_ind = dect_mncc_info_ind,
.mncc_alert_ind = dect_mncc_alert_ind,
.mncc_reject_ind = dect_mncc_reject_ind,
.dl_u_data_ind = dect_dl_u_data_ind,
};
static const struct dect_mm_ops mm_ops = {
.mm_access_rights_ind = 0,
.mm_access_rights_cfm = 0,
};
static struct dect_ops ops = {
.cc_ops = &cc_ops,
.mm_ops = &mm_ops,
};
int main(int argc, char **argv)
{
if (dect_event_ops_init(&ops) < 0)
exit(1);
dh = dect_alloc_handle(&ops);
if (dh == NULL)
exit(1);
if (dect_init(dh) < 0)
exit(1);
#if 0
//dect_lce_group_ring(dh, 0xf);
dect_open_call(dh, &ipuis[PHONE1]);
dect_open_call(dh, &ipuis[PHONE3]);
#else
dect_open_call(dh, &ipuis[PHONE2]);
#endif
dect_event_loop();
dect_close_handle(dh);
dect_event_ops_cleanup();
return 0;
}

3
include/Makefile.in Normal file
View File

@ -0,0 +1,3 @@
install:
install -d $(DESTDIR)/usr/include/dect
install -m 644 -t $(DESTDIR)/usr/include/dect/ include/dect/*

48
include/b_fmt.h Normal file
View File

@ -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 */

333
include/cc.h Normal file
View File

@ -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 */

15
include/coms.h Normal file
View File

@ -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 */

246
include/dect/cc.h Normal file
View File

@ -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 */

169
include/dect/identities.h Normal file
View File

@ -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 */

767
include/dect/ie.h Normal file
View File

@ -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 */

15
include/dect/keypad.h Normal file
View File

@ -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 */

134
include/dect/libdect.h Normal file
View File

@ -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 */

38
include/dect/mm.h Normal file
View File

@ -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 */

70
include/dect/terminal.h Normal file
View File

@ -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 */

8
include/dect/utils.h Normal file
View File

@ -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 */

121
include/identities.h Normal file
View File

@ -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 */

197
include/lce.h Normal file
View File

@ -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 */

35
include/libdect.h Normal file
View File

@ -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 */

76
include/linux/dect.h Normal file
View File

@ -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 */

306
include/linux/socket.h Normal file
View File

@ -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 */

625
include/list.h Normal file
View File

@ -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

167
include/mm.h Normal file
View File

@ -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 */

7
include/netlink.h Normal file
View File

@ -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 */

377
include/s_fmt.h Normal file
View File

@ -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 */

70
include/ss.h Normal file
View File

@ -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

70
include/utils.h Normal file
View File

@ -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 */

269
install-sh Executable file
View File

@ -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

1
src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
libdect.so

19
src/Makefile.in Normal file
View File

@ -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

1128
src/cc.c Normal file

File diff suppressed because it is too large Load Diff

94
src/ccitt-adpcm/README Normal file
View File

@ -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

113
src/ccitt-adpcm/decode.c Normal file
View File

@ -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);
}

119
src/ccitt-adpcm/encode.c Normal file
View File

@ -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);
}

285
src/ccitt-adpcm/g711.c Normal file
View File

@ -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)));
}

173
src/ccitt-adpcm/g721.c Normal file
View File

@ -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);
}
}

158
src/ccitt-adpcm/g723_24.c Normal file
View File

@ -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);
}
}

178
src/ccitt-adpcm/g723_40.c Normal file
View File

@ -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);
}
}

565
src/ccitt-adpcm/g72x.c Normal file
View File

@ -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);
}
}

148
src/ccitt-adpcm/g72x.h Normal file
View File

@ -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 */

211
src/dsaa.c Normal file
View File

@ -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);
}

182
src/identities.c Normal file
View File

@ -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;
}
}

80
src/keypad.c Normal file
View File

@ -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;
}

790
src/lce.c Normal file
View File

@ -0,0 +1,790 @@
/*
* DECT Link Control Entity (LCE)
*
* Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/byteorder/little_endian.h>
#include <linux/dect.h>
#include <asm/byteorder.h>
#include <libdect.h>
#include <identities.h>
#include <utils.h>
#include <s_fmt.h>
#include <b_fmt.h>
#include <lce.h>
#include <ss.h>
static const struct dect_sfmt_ie_desc lce_page_response_msg[] = {
DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_NONE, IE_MANDATORY, 0),
DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(S_VL_IE_NWK_ASSIGNED_IDENTITY, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(S_VL_IE_CIPHER_INFO, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_NONE, IE_OPTIONAL, 0),
DECT_SFMT_IE_END_MSG
};
static const struct dect_sfmt_ie_desc lce_page_reject_msg[] = {
DECT_SFMT_IE(S_VL_IE_PORTABLE_IDENTITY, IE_MANDATORY, IE_NONE, 0),
DECT_SFMT_IE(S_VL_IE_FIXED_IDENTITY, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(S_VL_IE_REJECT_REASON, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE(S_VL_IE_ESCAPE_TO_PROPRIETARY, IE_OPTIONAL, IE_NONE, 0),
DECT_SFMT_IE_END_MSG
};
static const struct dect_nwk_protocol *protocols[DECT_S_PD_MAX + 1];
void dect_lce_register_protocol(const struct dect_nwk_protocol *protocol)
{
protocols[protocol->pd] = protocol;
}
struct dect_msg_buf *dect_mbuf_alloc(const struct dect_handle *dh)
{
struct dect_msg_buf *mb;
mb = dect_malloc(dh, sizeof(*mb));
if (mb == NULL)
return NULL;
memset(mb->head, 0, sizeof(mb->head));
mb->data = mb->head;
mb->len = 0;
mb->type = 0;
return mb;
}
static ssize_t dect_mbuf_rcv(const struct dect_fd *dfd, struct dect_msg_buf *mb)
{
ssize_t len;
memset(mb, 0, sizeof(*mb));
mb->data = mb->head;
len = recv(dfd->fd, mb->data, sizeof(mb->head), 0);
if (len < 0)
return len;
mb->len = len;
return len;
}
#if 0
/*
* Location Table
*/
static struct dect_lte *dect_lte_get_by_ipui(const struct dect_handle *dh,
const struct dect_ipui *ipui)
{
struct dect_lte *lte;
list_for_each_entry(lte, &dh->ldb.entries, list) {
if (!dect_ipui_cmp(&lte->ipui, ipui))
return lte;
}
return NULL;
}
static struct dect_lte *dect_lte_alloc(const struct dect_handle *dh,
const struct dect_ipui *ipui)
{
struct dect_lte *lte;
lte = dect_malloc(dh, sizeof(*lte));
if (lte == NULL)
return NULL;
memcpy(&lte->ipui, ipui, sizeof(lte->ipui));
return lte;
}
#endif
/*
* Paging
*/
static int dect_lce_broadcast(const struct dect_handle *dh,
const uint8_t *msg, size_t len)
{
ssize_t size;
dect_hexdump("BROADCAST", msg, len);
size = send(dh->b_sap->fd, msg, len, 0);
assert(size == (ssize_t)len);
return 0;
}
int dect_lce_group_ring(struct dect_handle *dh, enum dect_ring_patterns pattern)
{
struct dect_short_page_msg msg;
uint16_t page;
msg.hdr = DECT_LCE_PAGE_W_FLAG;
msg.hdr |= DECT_LCE_PAGE_GENERAL_VOICE;
page = pattern << DECT_LCE_SHORT_PAGE_RING_PATTERN_SHIFT;
page = 0;
page |= DECT_TPUI_CBI & DECT_LCE_SHORT_PAGE_TPUI_MASK;
msg.information = __cpu_to_be16(page);
return dect_lce_broadcast(dh, &msg.hdr, sizeof(msg));
}
static int dect_lce_page(const struct dect_handle *dh,
const struct dect_ipui *ipui)
{
struct dect_short_page_msg msg;
struct dect_tpui tpui;
uint16_t page;
dect_default_individual_tpui(&tpui, ipui);
msg.hdr = DECT_LCE_PAGE_GENERAL_VOICE;
page = tpui.tpui & DECT_LCE_SHORT_PAGE_TPUI_MASK;
msg.information = __cpu_to_be16(page);
return dect_lce_broadcast(dh, &msg.hdr, sizeof(msg));
}
static void dect_lce_rcv_short_page(struct dect_handle *dh,
struct dect_msg_buf *mb)
{
struct dect_short_page_msg *msg = (void *)mb->data;
uint8_t hdr;
bool w;
w = msg->hdr & DECT_LCE_PAGE_W_FLAG;
hdr = msg->hdr & DECT_LCE_PAGE_HDR_MASK;
dect_debug("short page: w=%u hdr=%u information=%x\n",
w, hdr, __be16_to_cpu(msg->information));
}
static void dect_lce_bsap_event(struct dect_handle *dh, struct dect_fd *dfd,
uint32_t events)
{
struct dect_msg_buf _mb, *mb = &_mb;
if (dect_mbuf_rcv(dfd, mb) < 0)
return;
dect_mbuf_dump(mb, "BCAST RX");
switch (mb->len) {
case 3:
return dect_lce_rcv_short_page(dh, mb);
default:
break;
}
}
/*
* Data links
*/
#define ddl_debug(ddl, fmt, args...) \
dect_debug("link %d (%s): " fmt "\n", \
(ddl)->dfd ? (ddl)->dfd->fd : -1, \
ddl_states[(ddl)->state], ## args)
static const char *ddl_states[DECT_DATA_LINK_STATE_MAX + 1] = {
[DECT_DATA_LINK_RELEASED] = "RELEASED",
[DECT_DATA_LINK_ESTABLISHED] = "ESTABLISHED",
[DECT_DATA_LINK_ESTABLISH_PENDING] = "ESTABLISH_PENDING",
[DECT_DATA_LINK_RELEASE_PENDING] = "RELEASE_PENDING",
[DECT_DATA_LINK_SUSPENDED] = "SUSPENDED",
[DECT_DATA_LINK_SUSPEND_PENDING] = "SUSPEND_PENDING",
[DECT_DATA_LINK_RESUME_PENDING] = "RESUME_PENDING",
};
static struct dect_data_link *dect_ddl_get_by_ipui(const struct dect_handle *dh,
const struct dect_ipui *ipui)
{
struct dect_data_link *ddl;
list_for_each_entry(ddl, &dh->links, list) {
if (!dect_ipui_cmp(&ddl->ipui, ipui))
return ddl;
}
return NULL;
}
static struct dect_transaction *
dect_ddl_transaction_lookup(const struct dect_data_link *ddl, uint8_t pd, uint8_t tv)
{
struct dect_transaction *ta;
list_for_each_entry(ta, &ddl->transactions, list) {
if (ta->pd == pd && ta->tv == tv)
return ta;
}
return NULL;
}
static void dect_ddl_destroy(struct dect_handle *dh, struct dect_data_link *ddl)
{
struct dect_msg_buf *mb, *next;
ddl_debug(ddl, "destroy");
assert(ddl->sdu_timer == NULL);
assert(list_empty(&ddl->transactions));
list_del(&ddl->list);
list_for_each_entry_safe(mb, next, &ddl->msg_queue, list)
dect_free(dh, mb);
if (ddl->dfd != NULL) {
dect_unregister_fd(dh, ddl->dfd);
dect_close(dh, ddl->dfd);
}
dect_free(dh, ddl);
}
static struct dect_data_link *dect_ddl_alloc(const struct dect_handle *dh)
{
struct dect_data_link *ddl;
ddl = dect_zalloc(dh, sizeof(*ddl));
if (ddl == NULL)
return NULL;
ddl->state = DECT_DATA_LINK_RELEASED;
init_list_head(&ddl->list);
init_list_head(&ddl->transactions);
init_list_head(&ddl->msg_queue);
ddl_debug(ddl, "alloc");
return ddl;
}
static void dect_ddl_sdu_timer(struct dect_handle *dh, struct dect_timer *timer)
{
struct dect_data_link *ddl = timer->data;
ddl_debug(ddl, "SDU timer");
dect_free(dh, ddl->sdu_timer);
ddl->sdu_timer = NULL;
dect_ddl_destroy(dh, ddl);
}
static int dect_ddl_schedule_sdu_timer(const struct dect_handle *dh,
struct dect_data_link *ddl)
{
ddl->sdu_timer = dect_alloc_timer(dh);
if (ddl->sdu_timer == NULL)
return -1;
ddl->sdu_timer->data = ddl;
ddl->sdu_timer->callback = dect_ddl_sdu_timer;
dect_start_timer(dh, ddl->sdu_timer, DECT_DDL_ESTABLISH_SDU_TIMEOUT);
ddl_debug(ddl, "start SDU timer");
return 0;
}
static void dect_ddl_stop_sdu_timer(const struct dect_handle *dh,
struct dect_data_link *ddl)
{
ddl_debug(ddl, "stop SDU timer");
dect_stop_timer(dh, ddl->sdu_timer);
dect_free(dh, ddl->sdu_timer);
ddl->sdu_timer = NULL;
}
static int dect_send(const struct dect_handle *dh,
const struct dect_data_link *ddl,
struct dect_msg_buf *mb)
{
ssize_t len;
dect_mbuf_dump(mb, "TX");
len = send(ddl->dfd->fd, mb->data, mb->len, 0);
assert(len == (ssize_t)mb->len);
dect_free(dh, mb);
return len;
}
/**
* dect_send - Queue a S-Format message for transmission to the LCE
*
*/
int dect_lce_send(const struct dect_handle *dh,
const struct dect_transaction *ta,
const struct dect_sfmt_ie_desc *desc,
const struct dect_msg_common *msg, uint8_t type,
const char *prefix)
{
struct dect_data_link *ddl = ta->link;
struct dect_msg_buf *mb;
mb = dect_mbuf_alloc(dh);
if (mb == NULL)
return -1;
dect_mbuf_reserve(mb, DECT_S_HDR_SIZE);
dect_build_sfmt_msg(dh, desc, msg, mb);
if (ddl->sdu_timer != NULL)
dect_ddl_stop_sdu_timer(dh, ddl);
dect_mbuf_push(mb, DECT_S_HDR_SIZE);
mb->data[1] = type;
mb->data[0] = ta->pd;
mb->data[0] |= ta->tv << DECT_S_TI_TV_SHIFT;
if (ta->role == DECT_TRANSACTION_RESPONDER)
mb->data[0] |= DECT_S_TI_F_FLAG;
switch (ddl->state) {
case DECT_DATA_LINK_ESTABLISHED:
return dect_send(dh, ddl, mb);
case DECT_DATA_LINK_ESTABLISH_PENDING:
list_add_tail(&mb->list, &ddl->msg_queue);
return 0;
default:
BUG();
}
}
/**
* dect_ddl_establish - Establish an outgoing data link
*
*/
static void dect_lce_data_link_event(struct dect_handle *dh,
struct dect_fd *dfd, uint32_t events);
static struct dect_data_link *dect_ddl_establish(struct dect_handle *dh,
const struct dect_ipui *ipui)
{
struct dect_data_link *ddl;
//lte = dect_lte_get_by_ipui(dh, lte);
ddl = dect_ddl_alloc(dh);
if (ddl == NULL)
goto err1;
ddl->state = DECT_DATA_LINK_ESTABLISH_PENDING;
if (dh->mode == DECT_MODE_FP) {
memcpy(&ddl->ipui, ipui, sizeof(ddl->ipui));
dect_lce_page(dh, ipui);
} else {
ddl->dfd = dect_socket(dh, SOCK_SEQPACKET, DECT_S_SAP);
if (ddl->dfd == NULL)
goto err2;
ddl->dlei.dect_family = AF_DECT;
ddl->dlei.dect_ari = dect_build_ari(&dh->pari) >> 24;
ddl->dlei.dect_pmid = 0xe98a1;
ddl->dlei.dect_lln = 1;
ddl->dlei.dect_sapi = 0;
ddl->dfd->callback = dect_lce_data_link_event;
ddl->dfd->data = ddl;
if (dect_register_fd(dh, ddl->dfd, DECT_FD_WRITE) < 0)
goto err2;
if (connect(ddl->dfd->fd, (struct sockaddr *)&ddl->dlei,
sizeof(ddl->dlei)) < 0 && errno != EAGAIN)
perror("connect\n");
}
list_add_tail(&ddl->list, &dh->links);
return ddl;
err2:
dect_free(dh, ddl);
err1:
return NULL;
}
#if 0
int dect_send_reject(const struct dect_handle *dh,
const struct dect_transaction *ta,
enum dect_reject_reasons reason)
{
struct dect_ie_reject_reason reject_reason;
struct dect_lce_page_reject msg = {
.portable_identity = NULL,
.reject_reason = &reject_reason,
};
dect_send(dh, ta, mb);
}
#endif
static void dect_ddl_complete_direct_establish(struct dect_handle *dh,
struct dect_data_link *ddl)
{
struct dect_msg_buf *mb, *mb_next;
ddl->state = DECT_DATA_LINK_ESTABLISHED;
ddl_debug(ddl, "complete direct link establishment");
/* Send queued messages */
list_for_each_entry_safe(mb, mb_next, &ddl->msg_queue, list) {
list_del(&mb->list);
dect_send(dh, ddl, mb);
}
dect_unregister_fd(dh, ddl->dfd);
dect_register_fd(dh, ddl->dfd, DECT_FD_READ);
}
static void dect_ddl_complete_indirect_establish(struct dect_handle *dh,
struct dect_data_link *ddl,
struct dect_data_link *req)
{
struct dect_transaction *ta, *ta_next;
struct dect_msg_buf *mb, *mb_next;
ddl_debug(ddl, "complete indirect link establishment req %p", req);
/* Transfer transactions to the new link */
list_for_each_entry_safe(ta, ta_next, &req->transactions, list) {
ddl_debug(ta->link, "transfer transaction to link %p\n", ddl);
list_move_tail(&ta->list, &ddl->transactions);
ta->link = ddl;
}
/* Send queued messages */
list_for_each_entry_safe(mb, mb_next, &req->msg_queue, list) {
list_del(&mb->list);
dect_send(dh, ddl, mb);
}
/* Release pending link */
dect_ddl_destroy(dh, req);
}
static void dect_lce_rcv_page_response(struct dect_handle *dh,
const struct dect_transaction *ta,
struct dect_msg_buf *mb)
{
struct dect_lce_page_response msg;
struct dect_data_link *i, *req = NULL;
ddl_debug(ta->link, "LCE-PAGE-RESPONSE");
if (dect_parse_sfmt_msg(dh, lce_page_response_msg, &msg.common, mb) < 0)
return;
dect_debug("portable_identity: %p\n", msg.portable_identity);
dect_debug("fixed identity: %p\n", msg.fixed_identity);
dect_debug("nwk assigned identity: %p\n", msg.nwk_assigned_identity);
dect_debug("cipher info: %p\n", msg.cipher_info);
dect_debug("escape: %p\n", msg.escape_to_proprietary);
list_for_each_entry(i, &dh->links, list) {
if (dect_ipui_cmp(&i->ipui, &msg.portable_identity->ipui))
continue;
if (i->state != DECT_DATA_LINK_ESTABLISH_PENDING)
continue;
req = i;
break;
}
if (req != NULL)
dect_ddl_complete_indirect_establish(dh, ta->link, req);
else {
/* send page reject */
dect_ddl_destroy(dh, ta->link);
}
dect_msg_free(dh, lce_page_response_msg, &msg.common);
}
static void dect_lce_rcv_page_reject(struct dect_handle *dh,
struct dect_transaction *ta,
struct dect_msg_buf *mb)
{
struct dect_lce_page_reject msg;
ddl_debug(ta->link, "LCE-PAGE-REJECT");
if (dect_parse_sfmt_msg(dh, lce_page_reject_msg, &msg.common, mb) < 0)
return;
dect_msg_free(dh, lce_page_reject_msg, &msg.common);
}
static void dect_lce_rcv(struct dect_handle *dh, struct dect_transaction *ta,
struct dect_msg_buf *mb)
{
switch (mb->type) {
case DECT_LCE_PAGE_REJECT:
return dect_lce_rcv_page_reject(dh, ta, mb);
default:
ddl_debug(ta->link, "LCE: unknown message type %x", mb->type);
return;
}
}
static void dect_lce_open(struct dect_handle *dh,
const struct dect_transaction *ta,
struct dect_msg_buf *mb)
{
switch (mb->type) {
case DECT_LCE_PAGE_RESPONSE:
return dect_lce_rcv_page_response(dh, ta, mb);
default:
ddl_debug(ta->link, "LCE: unknown message type %x", mb->type);
return;
}
}
static const struct dect_nwk_protocol lce_protocol = {
.name = "Link Control",
.pd = DECT_S_PD_LCE,
.max_transactions = 1,
.open = dect_lce_open,
.rcv = dect_lce_rcv,
};
static void dect_ddl_rcv_msg(struct dect_handle *dh, struct dect_data_link *ddl)
{
struct dect_msg_buf _mb, *mb = &_mb;
struct dect_transaction *ta;
uint8_t pd, tv;
bool f;
if (ddl->sdu_timer != NULL)
dect_ddl_stop_sdu_timer(dh, ddl);
if (dect_mbuf_rcv(ddl->dfd, mb) < 0)
return;
dect_mbuf_dump(mb, "RX");
if (mb->len < DECT_S_HDR_SIZE)
return;
f = (mb->data[0] & DECT_S_TI_F_FLAG);
tv = (mb->data[0] & DECT_S_TI_TV_MASK) >> DECT_S_TI_TV_SHIFT;
pd = (mb->data[0] & DECT_S_PD_MASK);
mb->type = (mb->data[1] & DECT_S_PD_MSG_TYPE_MASK);
dect_mbuf_pull(mb, DECT_S_HDR_SIZE);
if (pd >= array_size(protocols) || protocols[pd] == NULL) {
ddl_debug(ddl, "unknown protocol %u\n", pd);
return;
}
if (tv == DECT_TV_CONNECTIONLESS)
return dect_clss_rcv(dh, mb);
ta = dect_ddl_transaction_lookup(ddl, pd, tv);
if (ta == NULL) {
struct dect_transaction req = {
.link = ddl,
.pd = pd,
.role = DECT_TRANSACTION_RESPONDER,
.tv = tv,
};
ddl_debug(ddl, "new transaction: protocol: %s F: %u TV: %u",
protocols[pd]->name, f, tv);
protocols[pd]->open(dh, &req, mb);
} else
protocols[pd]->rcv(dh, ta, mb);
}
static void dect_lce_data_link_event(struct dect_handle *dh,
struct dect_fd *dfd, uint32_t events)
{
struct dect_data_link *ddl = dfd->data;
if (events & DECT_FD_WRITE) {
switch (ddl->state) {
case DECT_DATA_LINK_ESTABLISH_PENDING:
dect_ddl_complete_direct_establish(dh, ddl);
break;
default:
break;
}
}
if (events & DECT_FD_READ) {
dect_ddl_rcv_msg(dh, ddl);
}
}
static int dect_transaction_alloc_tv(const struct dect_data_link *ddl,
const struct dect_nwk_protocol *protocol)
{
uint16_t tv;
for (tv = 0; tv < protocol->max_transactions; tv++) {
if (dect_ddl_transaction_lookup(ddl, protocol->pd, tv))
continue;
return tv;
}
return -1;
}
int dect_open_transaction(struct dect_handle *dh, struct dect_transaction *ta,
const struct dect_ipui *ipui)
{
struct dect_data_link *ddl;
int tv;
ddl = dect_ddl_get_by_ipui(dh, ipui);
if (ddl == NULL) {
ddl = dect_ddl_establish(dh, ipui);
if (ddl == NULL)
return -1;
}
ddl_debug(ddl, "open transaction");
tv = dect_transaction_alloc_tv(ddl, protocols[ta->pd]);
if (tv < 0)
return -1;
ta->link = ddl;
ta->role = DECT_TRANSACTION_INITIATOR;
ta->tv = tv;
list_add_tail(&ta->list, &ddl->transactions);
return 0;
}
void dect_confirm_transaction(struct dect_handle *dh, struct dect_transaction *ta,
const struct dect_transaction *req)
{
ta->link = req->link;
ta->tv = req->tv;
ta->role = req->role;
ta->pd = req->pd;
ddl_debug(req->link, "confirm transaction");
list_add_tail(&ta->list, &req->link->transactions);
}
void dect_close_transaction(struct dect_handle *dh, struct dect_transaction *ta)
{
struct dect_data_link *ddl = ta->link;
ddl_debug(ddl, "close transaction");
list_del(&ta->list);
list_for_each_entry(ta, &ddl->transactions, list)
dect_debug("\ttrans %p proto %u TV %u\n", ta, ta->pd, ta->tv);
if (!list_empty(&ddl->transactions))
return;
dect_ddl_destroy(dh, ddl);
}
void dect_transaction_get_ulei(struct sockaddr_dect_lu *addr,
const struct dect_transaction *ta)
{
struct dect_data_link *ddl = ta->link;
memset(addr, 0, sizeof(*addr));
addr->dect_family = AF_DECT;
addr->dect_ari = ddl->dlei.dect_ari;
addr->dect_pmid = ddl->dlei.dect_pmid;
addr->dect_lcn = ddl->dlei.dect_lcn;
}
static void dect_lce_ssap_listener_event(struct dect_handle *dh,
struct dect_fd *dfd, uint32_t events)
{
struct dect_data_link *ddl;
struct dect_fd *nfd;
ddl = dect_ddl_alloc(dh);
if (ddl == NULL)
goto err1;
nfd = dect_accept(dh, dfd, (struct sockaddr *)&ddl->dlei,
sizeof(ddl->dlei));
if (nfd == NULL)
goto err2;
ddl->dfd = nfd;
nfd->callback = dect_lce_data_link_event;
nfd->data = ddl;
if (dect_register_fd(dh, nfd, DECT_FD_READ) < 0)
goto err3;
ddl->state = DECT_DATA_LINK_ESTABLISHED;
if (dect_ddl_schedule_sdu_timer(dh, ddl) < 0)
goto err4;
list_add_tail(&ddl->list, &dh->links);
ddl_debug(ddl, "new link: PMID: %x LCN: %u LLN: %u SAPI: %u",
ddl->dlei.dect_pmid, ddl->dlei.dect_lcn,
ddl->dlei.dect_lln, ddl->dlei.dect_sapi);
return;
err4:
dect_unregister_fd(dh, nfd);
err3:
dect_close(dh, nfd);
err2:
dect_free(dh, ddl);
err1:
return;
}
int dect_lce_init(struct dect_handle *dh)
{
struct sockaddr_dect_ssap s_addr;
struct sockaddr_dect b_addr;
/* Open B-SAP socket */
dh->b_sap = dect_socket(dh, SOCK_DGRAM, DECT_B_SAP);
if (dh->b_sap == NULL)
goto err1;
b_addr.dect_family = AF_DECT;
b_addr.dect_index = dh->index;
if (bind(dh->b_sap->fd, (struct sockaddr *)&b_addr, sizeof(b_addr)) < 0)
goto err2;
dh->b_sap->callback = dect_lce_bsap_event;
if (dect_register_fd(dh, dh->b_sap, DECT_FD_READ) < 0)
goto err2;
/* Open S-SAP listener socket */
dh->s_sap = dect_socket(dh, SOCK_SEQPACKET, DECT_S_SAP);
if (dh->s_sap == NULL)
goto err3;
memset(&s_addr, 0, sizeof(s_addr));
s_addr.dect_family = AF_DECT;
s_addr.dect_lln = 1;
s_addr.dect_sapi = 0;
if (bind(dh->s_sap->fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0)
goto err4;
if (listen(dh->s_sap->fd, 10) < 0)
goto err4;
dh->s_sap->callback = dect_lce_ssap_listener_event;
if (dect_register_fd(dh, dh->s_sap, DECT_FD_READ) < 0)
goto err4;
protocols[DECT_S_PD_LCE] = &lce_protocol;
return 0;
err4:
dect_close(dh, dh->s_sap);
err3:
dect_unregister_fd(dh, dh->b_sap);
err2:
dect_close(dh, dh->b_sap);
err1:
return -1;
}
void dect_lce_exit(struct dect_handle *dh)
{
struct dect_data_link *ddl, *ddl_next;
struct dect_transaction *ta, *ta_next;
LIST_HEAD(transactions);
list_for_each_entry_safe(ddl, ddl_next, &dh->links, list) {
ddl_debug(ddl, "shutdown");
list_splice_init(&ddl->transactions, &transactions);
list_for_each_entry_safe(ta, ta_next, &transactions, list)
protocols[ta->pd]->shutdown(dh, ta);
}
dect_unregister_fd(dh, dh->s_sap);
dect_close(dh, dh->s_sap);
dect_unregister_fd(dh, dh->b_sap);
dect_close(dh, dh->b_sap);
}

81
src/libdect.c Normal file
View File

@ -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);
}

154
src/mm.c Normal file
View File

@ -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);
}

139
src/netlink.c Normal file
View File

@ -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);
}

991
src/s_msg.c Normal file
View File

@ -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++;
}
}

49
src/ss.c Normal file
View File

@ -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;
}

142
src/utils.c Normal file
View File

@ -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;
}