Add 'src/shared/libosmocore/' from commit '3cae0398eaef6045de883849a236c38d1767cb41'
authorHarald Welte <laforge@gnumonks.org>
Sat, 20 Feb 2010 20:09:43 +0000 (21:09 +0100)
committerHarald Welte <laforge@gnumonks.org>
Sat, 20 Feb 2010 20:09:43 +0000 (21:09 +0100)
git-subtree-dir: src/shared/libosmocore
git-subtree-mainline: e54eb7c17c648fe481053df9fea580b92a0a7701
git-subtree-split: 3cae0398eaef6045de883849a236c38d1767cb41

41 files changed:
1  2 
src/shared/libosmocore/.gitignore
src/shared/libosmocore/Makefile.am
src/shared/libosmocore/configure.in
src/shared/libosmocore/include/Makefile.am
src/shared/libosmocore/include/osmocore/Makefile.am
src/shared/libosmocore/include/osmocore/bitvec.h
src/shared/libosmocore/include/osmocore/comp128.h
src/shared/libosmocore/include/osmocore/gsm_utils.h
src/shared/libosmocore/include/osmocore/gsmtap.h
src/shared/libosmocore/include/osmocore/linuxlist.h
src/shared/libosmocore/include/osmocore/msgb.h
src/shared/libosmocore/include/osmocore/protocol/Makefile.am
src/shared/libosmocore/include/osmocore/protocol/gsm_04_08.h
src/shared/libosmocore/include/osmocore/protocol/gsm_04_11.h
src/shared/libosmocore/include/osmocore/protocol/gsm_04_80.h
src/shared/libosmocore/include/osmocore/protocol/gsm_08_58.h
src/shared/libosmocore/include/osmocore/protocol/gsm_12_21.h
src/shared/libosmocore/include/osmocore/select.h
src/shared/libosmocore/include/osmocore/signal.h
src/shared/libosmocore/include/osmocore/statistics.h
src/shared/libosmocore/include/osmocore/talloc.h
src/shared/libosmocore/include/osmocore/timer.h
src/shared/libosmocore/include/osmocore/tlv.h
src/shared/libosmocore/include/osmocore/utils.h
src/shared/libosmocore/libosmocore.pc.in
src/shared/libosmocore/src/Makefile.am
src/shared/libosmocore/src/bitvec.c
src/shared/libosmocore/src/comp128.c
src/shared/libosmocore/src/gsm_utils.c
src/shared/libosmocore/src/msgb.c
src/shared/libosmocore/src/select.c
src/shared/libosmocore/src/signal.c
src/shared/libosmocore/src/statistics.c
src/shared/libosmocore/src/talloc.c
src/shared/libosmocore/src/timer.c
src/shared/libosmocore/src/tlv_parser.c
src/shared/libosmocore/tests/Makefile.am
src/shared/libosmocore/tests/sms/Makefile.am
src/shared/libosmocore/tests/sms/sms_test.c
src/shared/libosmocore/tests/timer/Makefile.am
src/shared/libosmocore/tests/timer/timer_test.c

index 0000000,0000000..c292a61
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++Makefile
++Makefile.in
++.deps
++.libs
++*.o
++*.lo
++*.la
++*.pc
++aclocal.m4
++autom4te.cache
++config.h*
++config.sub
++config.log
++config.status
++config.guess
++configure
++depcomp
++missing
++ltmain.sh
++install-sh
++stamp-h1
++libtool
index 0000000,0000000..8007b74
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
++
++INCLUDES = $(all_includes) -I$(top_srcdir)/include
++SUBDIRS = include src tests
++
++pkgconfigdir = $(libdir)/pkgconfig
++pkgconfig_DATA = libosmocore.pc
index 0000000,0000000..a5c5f6b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,42 @@@
++AC_INIT
++
++AM_INIT_AUTOMAKE(libosmocore, 0.0alpha1)
++
++dnl kernel style compile messages
++m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
++
++dnl checks for programs
++AC_PROG_MAKE_SET
++AC_PROG_CC
++AC_PROG_INSTALL
++AC_PROG_RANLIB
++AC_PROG_LIBTOOL
++
++dnl checks for header files
++AC_HEADER_STDC
++AC_CHECK_HEADERS(execinfo.h sys/select.h)
++
++# The following test is taken from WebKit's webkit.m4
++saved_CFLAGS="$CFLAGS"
++CFLAGS="$CFLAGS -fvisibility=hidden "
++AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
++AC_COMPILE_IFELSE([char foo;],
++      [ AC_MSG_RESULT([yes])
++        SYMBOL_VISIBILITY="-fvisibility=hidden"],
++        AC_MSG_RESULT([no]))
++CFLAGS="$saved_CFLAGS"
++AC_SUBST(SYMBOL_VISIBILITY)
++
++dnl Generate the output
++AM_CONFIG_HEADER(config.h)
++
++AC_OUTPUT(
++      libosmocore.pc
++      include/osmocore/Makefile
++      include/osmocore/protocol/Makefile
++      include/Makefile
++      src/Makefile
++      tests/Makefile
++      tests/timer/Makefile
++      tests/sms/Makefile
++      Makefile)
index 0000000,0000000..f0015d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++SUBDIRS = osmocore
index 0000000,0000000..0211752
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++osmocore_HEADERS = signal.h linuxlist.h timer.h talloc.h msgb.h select.h \
++                 tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \
++                 gsmtap.h
++
++osmocoredir = $(includedir)/osmocore
++
++SUBDIRS = protocol
index 0000000,0000000..11cb01e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,65 @@@
++#ifndef _BITVEC_H
++#define _BITVEC_H
++
++/* bit vector utility routines */
++
++/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++
++/* In GSM mac blocks, every bit can be 0 or 1, or L or H.  L/H are
++ * defined relative to the 0x2b padding pattern */
++enum bit_value {
++      ZERO    = 0,
++      ONE     = 1,
++      L       = 2,
++      H       = 3,
++};
++
++struct bitvec {
++      unsigned int cur_bit;   /* curser to the next unused bit */
++      unsigned int data_len;  /* length of data array in bytes */
++      uint8_t *data;          /* pointer to data array */
++};
++
++/* check if the bit is 0 or 1 for a given position inside a bitvec */
++enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr);
++
++/* get the Nth set bit inside the bit vector */
++unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n);
++
++/* Set a bit at given position */
++int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
++                      enum bit_value bit);
++
++/* Set the next bit in the vector */
++int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
++
++/* Set multiple bits at the current position */
++int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count);
++
++/* Add an unsigned integer (of length count bits) to current position */
++int bitvec_set_uint(struct bitvec *bv, unsigned int in, int count);
++
++
++/* Pad the bit vector up to a certain bit position */
++int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit);
++
++#endif /* _BITVEC_H */
index 0000000,0000000..c37808f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++/*
++ * COMP128 header
++ *
++ * See comp128.c for details
++ */
++
++#ifndef __COMP128_H__
++#define __COMP128_H__
++
++#include <stdint.h>
++
++/*
++ * Performs the COMP128 algorithm (used as A3/A8)
++ * ki    : uint8_t [16]
++ * srand : uint8_t [16]
++ * sres  : uint8_t [4]
++ * kc    : uint8_t [8]
++ */
++void comp128(uint8_t *ki, uint8_t *srand, uint8_t *sres, uint8_t *kc);
++
++#endif /* __COMP128_H__ */
++
index 0000000,0000000..57521ac
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,59 @@@
++/* GSM utility functions, e.g. coding and decoding */
++/*
++ * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
++ * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
++ * (C) 2009 by Harald Welte <laforge@gnumonks.org>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef GSM_UTILS_H
++#define GSM_UTILS_H
++
++#include <stdint.h>
++
++enum gsm_band {
++      GSM_BAND_850    = 1,
++      GSM_BAND_900    = 2,
++      GSM_BAND_1800   = 4,
++      GSM_BAND_1900   = 8,
++      GSM_BAND_450    = 0x10,
++      GSM_BAND_480    = 0x20,
++      GSM_BAND_750    = 0x40,
++      GSM_BAND_810    = 0x80,
++};
++
++int gsm_7bit_decode(char *decoded, const uint8_t *user_data, uint8_t length);
++int gsm_7bit_encode(uint8_t *result, const char *data);
++
++int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm);
++int ms_pwr_dbm(enum gsm_band band, uint8_t lvl);
++
++/* According to TS 08.05 Chapter 8.1.4 */
++int rxlev2dbm(uint8_t rxlev);
++uint8_t dbm2rxlev(int dbm);
++
++/* According to GSM 04.08 Chapter 10.5.2.29 */
++static inline int rach_max_trans_val2raw(int val) { return (val >> 1) & 3; }
++static inline int rach_max_trans_raw2val(int raw) {
++      const int tbl[4] = { 1, 2, 4, 7 };
++      return tbl[raw & 3];
++}
++
++void generate_backtrace();
++#endif
index 0000000,0000000..81b9cc0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,62 @@@
++#ifndef _GSMTAP_H
++#define _GSMTAP_H
++
++/* gsmtap header, pseudo-header in front of the actua GSM payload*/
++
++#include <stdint.h>
++
++#define GSMTAP_VERSION                0x01
++
++#define GSMTAP_TYPE_UM                0x01
++#define GSMTAP_TYPE_ABIS      0x02
++#define GSMTAP_TYPE_UM_BURST  0x03    /* raw burst bits */
++
++#define GSMTAP_BURST_UNKNOWN          0x00
++#define GSMTAP_BURST_FCCH             0x01
++#define GSMTAP_BURST_PARTIAL_SCH      0x02
++#define GSMTAP_BURST_SCH              0x03
++#define GSMTAP_BURST_CTS_SCH          0x04
++#define GSMTAP_BURST_COMPACT_SCH      0x05
++#define GSMTAP_BURST_NORMAL           0x06
++#define GSMTAP_BURST_DUMMY            0x07
++#define GSMTAP_BURST_ACCESS           0x08
++#define GSMTAP_BURST_NONE             0x09
++
++#define GSMTAP_UDP_PORT                 4729
++
++struct gsmtap_hdr {
++      uint8_t version;                /* version, set to 0x01 currently */
++      uint8_t hdr_len;                /* length in number of 32bit words */
++      uint8_t type;                   /* see GSMTAP_TYPE_* */
++      uint8_t timeslot;               /* timeslot (0..7 on Um) */
++
++      uint16_t arfcn;                 /* ARFCN (frequency) */
++      uint8_t noise_db;               /* noise figure in dB */
++      uint8_t signal_db;              /* signal level in dB */
++
++      uint32_t frame_number;          /* GSM Frame Number (FN) */
++
++      uint8_t burst_type;             /* Type of burst, see above */
++      uint8_t antenna_nr;             /* Antenna Number */
++      uint16_t res;                   /* reserved for future use (RFU) */
++
++} __attribute__((packed));
++
++
++/* PCAP related definitions */
++#define TCPDUMP_MAGIC   0xa1b2c3d4
++#ifndef LINKTYPE_GSMTAP
++#define LINKTYPE_GSMTAP       2342
++#endif
++struct pcap_timeval {
++      int32_t tv_sec;
++      int32_t tv_usec;
++};
++
++struct pcap_sf_pkthdr {
++      struct pcap_timeval ts;         /* time stamp */
++      uint32_t caplen;                /* lenght of portion present */
++      uint32_t len;                   /* length of this packet */
++};
++
++#endif /* _GSMTAP_H */
index 0000000,0000000..fb99c5e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,360 @@@
++#ifndef _LINUX_LLIST_H
++#define _LINUX_LLIST_H
++
++#include <stddef.h>
++
++#ifndef inline
++#define inline __inline__
++#endif
++
++static inline void prefetch(const void *x) {;}
++
++/**
++ * container_of - cast a member of a structure out to the containing structure
++ *
++ * @ptr:      the pointer to the member.
++ * @type:     the type of the container struct this is embedded in.
++ * @member:   the name of the member within the struct.
++ *
++ */
++#define container_of(ptr, type, member) ({                    \
++        const typeof( ((type *)0)->member ) *__mptr = (typeof( ((type *)0)->member ) *)(ptr); \
++        (type *)( (char *)__mptr - offsetof(type, member) );})
++
++
++/*
++ * These are non-NULL pointers that will result in page faults
++ * under normal circumstances, used to verify that nobody uses
++ * non-initialized llist entries.
++ */
++#define LLIST_POISON1  ((void *) 0x00100100)
++#define LLIST_POISON2  ((void *) 0x00200200)
++
++/*
++ * Simple doubly linked llist implementation.
++ *
++ * Some of the internal functions ("__xxx") are useful when
++ * manipulating whole llists 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 llist_head {
++      struct llist_head *next, *prev;
++};
++
++#define LLIST_HEAD_INIT(name) { &(name), &(name) }
++
++#define LLIST_HEAD(name) \
++      struct llist_head name = LLIST_HEAD_INIT(name)
++
++#define INIT_LLIST_HEAD(ptr) do { \
++      (ptr)->next = (ptr); (ptr)->prev = (ptr); \
++} while (0)
++
++/*
++ * Insert a new entry between two known consecutive entries. 
++ *
++ * This is only for internal llist manipulation where we know
++ * the prev/next entries already!
++ */
++static inline void __llist_add(struct llist_head *_new,
++                            struct llist_head *prev,
++                            struct llist_head *next)
++{
++      next->prev = _new;
++      _new->next = next;
++      _new->prev = prev;
++      prev->next = _new;
++}
++
++/**
++ * llist_add - add a new entry
++ * @new: new entry to be added
++ * @head: llist head to add it after
++ *
++ * Insert a new entry after the specified head.
++ * This is good for implementing stacks.
++ */
++static inline void llist_add(struct llist_head *_new, struct llist_head *head)
++{
++      __llist_add(_new, head, head->next);
++}
++
++/**
++ * llist_add_tail - add a new entry
++ * @new: new entry to be added
++ * @head: llist head to add it before
++ *
++ * Insert a new entry before the specified head.
++ * This is useful for implementing queues.
++ */
++static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head)
++{
++      __llist_add(_new, head->prev, head);
++}
++
++/*
++ * Delete a llist entry by making the prev/next entries
++ * point to each other.
++ *
++ * This is only for internal llist manipulation where we know
++ * the prev/next entries already!
++ */
++static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
++{
++      next->prev = prev;
++      prev->next = next;
++}
++
++/**
++ * llist_del - deletes entry from llist.
++ * @entry: the element to delete from the llist.
++ * Note: llist_empty on entry does not return true after this, the entry is
++ * in an undefined state.
++ */
++static inline void llist_del(struct llist_head *entry)
++{
++      __llist_del(entry->prev, entry->next);
++      entry->next = (struct llist_head *)LLIST_POISON1;
++      entry->prev = (struct llist_head *)LLIST_POISON2;
++}
++
++/**
++ * llist_del_init - deletes entry from llist and reinitialize it.
++ * @entry: the element to delete from the llist.
++ */
++static inline void llist_del_init(struct llist_head *entry)
++{
++      __llist_del(entry->prev, entry->next);
++      INIT_LLIST_HEAD(entry); 
++}
++
++/**
++ * llist_move - delete from one llist and add as another's head
++ * @llist: the entry to move
++ * @head: the head that will precede our entry
++ */
++static inline void llist_move(struct llist_head *llist, struct llist_head *head)
++{
++        __llist_del(llist->prev, llist->next);
++        llist_add(llist, head);
++}
++
++/**
++ * llist_move_tail - delete from one llist and add as another's tail
++ * @llist: the entry to move
++ * @head: the head that will follow our entry
++ */
++static inline void llist_move_tail(struct llist_head *llist,
++                                struct llist_head *head)
++{
++        __llist_del(llist->prev, llist->next);
++        llist_add_tail(llist, head);
++}
++
++/**
++ * llist_empty - tests whether a llist is empty
++ * @head: the llist to test.
++ */
++static inline int llist_empty(const struct llist_head *head)
++{
++      return head->next == head;
++}
++
++static inline void __llist_splice(struct llist_head *llist,
++                               struct llist_head *head)
++{
++      struct llist_head *first = llist->next;
++      struct llist_head *last = llist->prev;
++      struct llist_head *at = head->next;
++
++      first->prev = head;
++      head->next = first;
++
++      last->next = at;
++      at->prev = last;
++}
++
++/**
++ * llist_splice - join two llists
++ * @llist: the new llist to add.
++ * @head: the place to add it in the first llist.
++ */
++static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
++{
++      if (!llist_empty(llist))
++              __llist_splice(llist, head);
++}
++
++/**
++ * llist_splice_init - join two llists and reinitialise the emptied llist.
++ * @llist: the new llist to add.
++ * @head: the place to add it in the first llist.
++ *
++ * The llist at @llist is reinitialised
++ */
++static inline void llist_splice_init(struct llist_head *llist,
++                                  struct llist_head *head)
++{
++      if (!llist_empty(llist)) {
++              __llist_splice(llist, head);
++              INIT_LLIST_HEAD(llist);
++      }
++}
++
++/**
++ * llist_entry - get the struct for this entry
++ * @ptr:      the &struct llist_head pointer.
++ * @type:     the type of the struct this is embedded in.
++ * @member:   the name of the llist_struct within the struct.
++ */
++#define llist_entry(ptr, type, member) \
++      container_of(ptr, type, member)
++
++/**
++ * llist_for_each     -       iterate over a llist
++ * @pos:      the &struct llist_head to use as a loop counter.
++ * @head:     the head for your llist.
++ */
++#define llist_for_each(pos, head) \
++      for (pos = (head)->next, prefetch(pos->next); pos != (head); \
++              pos = pos->next, prefetch(pos->next))
++
++/**
++ * __llist_for_each   -       iterate over a llist
++ * @pos:      the &struct llist_head to use as a loop counter.
++ * @head:     the head for your llist.
++ *
++ * This variant differs from llist_for_each() in that it's the
++ * simplest possible llist iteration code, no prefetching is done.
++ * Use this for code that knows the llist to be very short (empty
++ * or 1 entry) most of the time.
++ */
++#define __llist_for_each(pos, head) \
++      for (pos = (head)->next; pos != (head); pos = pos->next)
++
++/**
++ * llist_for_each_prev        -       iterate over a llist backwards
++ * @pos:      the &struct llist_head to use as a loop counter.
++ * @head:     the head for your llist.
++ */
++#define llist_for_each_prev(pos, head) \
++      for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
++              pos = pos->prev, prefetch(pos->prev))
++              
++/**
++ * llist_for_each_safe        -       iterate over a llist safe against removal of llist entry
++ * @pos:      the &struct llist_head to use as a loop counter.
++ * @n:                another &struct llist_head to use as temporary storage
++ * @head:     the head for your llist.
++ */
++#define llist_for_each_safe(pos, n, head) \
++      for (pos = (head)->next, n = pos->next; pos != (head); \
++              pos = n, n = pos->next)
++
++/**
++ * llist_for_each_entry       -       iterate over llist of given type
++ * @pos:      the type * to use as a loop counter.
++ * @head:     the head for your llist.
++ * @member:   the name of the llist_struct within the struct.
++ */
++#define llist_for_each_entry(pos, head, member)                               \
++      for (pos = llist_entry((head)->next, typeof(*pos), member),     \
++                   prefetch(pos->member.next);                        \
++           &pos->member != (head);                                    \
++           pos = llist_entry(pos->member.next, typeof(*pos), member), \
++                   prefetch(pos->member.next))
++
++/**
++ * llist_for_each_entry_reverse - iterate backwards over llist of given type.
++ * @pos:      the type * to use as a loop counter.
++ * @head:     the head for your llist.
++ * @member:   the name of the llist_struct within the struct.
++ */
++#define llist_for_each_entry_reverse(pos, head, member)                       \
++      for (pos = llist_entry((head)->prev, typeof(*pos), member),     \
++                   prefetch(pos->member.prev);                        \
++           &pos->member != (head);                                    \
++           pos = llist_entry(pos->member.prev, typeof(*pos), member), \
++                   prefetch(pos->member.prev))
++
++/**
++ * llist_for_each_entry_continue -    iterate over llist of given type
++ *                    continuing after existing point
++ * @pos:      the type * to use as a loop counter.
++ * @head:     the head for your llist.
++ * @member:   the name of the llist_struct within the struct.
++ */
++#define llist_for_each_entry_continue(pos, head, member)              \
++      for (pos = llist_entry(pos->member.next, typeof(*pos), member), \
++                   prefetch(pos->member.next);                        \
++           &pos->member != (head);                                    \
++           pos = llist_entry(pos->member.next, typeof(*pos), member), \
++                   prefetch(pos->member.next))
++
++/**
++ * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry
++ * @pos:      the type * to use as a loop counter.
++ * @n:                another type * to use as temporary storage
++ * @head:     the head for your llist.
++ * @member:   the name of the llist_struct within the struct.
++ */
++#define llist_for_each_entry_safe(pos, n, head, member)                       \
++      for (pos = llist_entry((head)->next, typeof(*pos), member),     \
++              n = llist_entry(pos->member.next, typeof(*pos), member);        \
++           &pos->member != (head);                                    \
++           pos = n, n = llist_entry(n->member.next, typeof(*n), member))
++
++/**
++ * llist_for_each_rcu -       iterate over an rcu-protected llist
++ * @pos:      the &struct llist_head to use as a loop counter.
++ * @head:     the head for your llist.
++ */
++#define llist_for_each_rcu(pos, head) \
++      for (pos = (head)->next, prefetch(pos->next); pos != (head); \
++              pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
++              
++#define __llist_for_each_rcu(pos, head) \
++      for (pos = (head)->next; pos != (head); \
++              pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
++              
++/**
++ * llist_for_each_safe_rcu    -       iterate over an rcu-protected llist safe
++ *                                    against removal of llist entry
++ * @pos:      the &struct llist_head to use as a loop counter.
++ * @n:                another &struct llist_head to use as temporary storage
++ * @head:     the head for your llist.
++ */
++#define llist_for_each_safe_rcu(pos, n, head) \
++      for (pos = (head)->next, n = pos->next; pos != (head); \
++              pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
++
++/**
++ * llist_for_each_entry_rcu   -       iterate over rcu llist of given type
++ * @pos:      the type * to use as a loop counter.
++ * @head:     the head for your llist.
++ * @member:   the name of the llist_struct within the struct.
++ */
++#define llist_for_each_entry_rcu(pos, head, member)                   \
++      for (pos = llist_entry((head)->next, typeof(*pos), member),     \
++                   prefetch(pos->member.next);                        \
++           &pos->member != (head);                                    \
++           pos = llist_entry(pos->member.next, typeof(*pos), member), \
++                   ({ smp_read_barrier_depends(); 0;}),               \
++                   prefetch(pos->member.next))
++
++
++/**
++ * llist_for_each_continue_rcu        -       iterate over an rcu-protected llist 
++ *                    continuing after existing point.
++ * @pos:      the &struct llist_head to use as a loop counter.
++ * @head:     the head for your llist.
++ */
++#define llist_for_each_continue_rcu(pos, head) \
++      for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
++              (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
++
++
++#endif
index 0000000,0000000..131f920
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,114 @@@
++#ifndef _MSGB_H
++#define _MSGB_H
++
++/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <stdint.h>
++#include "linuxlist.h"
++
++struct bts_link;
++
++struct msgb {
++      struct llist_head list;
++
++      /* ptr to the physical E1 link to the BTS(s) */
++      struct gsm_bts_link *bts_link;
++
++      /* Part of which TRX logical channel we were received / transmitted */
++      struct gsm_bts_trx *trx;
++      struct gsm_lchan *lchan;
++
++      unsigned char *l2h;
++      unsigned char *l3h;
++      unsigned char *smsh;
++
++      uint16_t data_len;
++      uint16_t len;
++
++      unsigned char *head;
++      unsigned char *tail;
++      unsigned char *data;
++      unsigned char _data[0];
++};
++
++extern struct msgb *msgb_alloc(uint16_t size, const char *name);
++extern void msgb_free(struct msgb *m);
++extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
++extern struct msgb *msgb_dequeue(struct llist_head *queue);
++extern void msgb_reset(struct msgb *m);
++
++#define msgb_l2(m)    ((void *)(m->l2h))
++#define msgb_l3(m)    ((void *)(m->l3h))
++#define msgb_sms(m)   ((void *)(m->smsh))
++
++static inline unsigned int msgb_l2len(const struct msgb *msgb)
++{
++      return msgb->tail - (uint8_t *)msgb_l2(msgb);
++}
++
++static inline unsigned int msgb_l3len(const struct msgb *msgb)
++{
++      return msgb->tail - (uint8_t *)msgb_l3(msgb);
++}
++
++static inline unsigned int msgb_headlen(const struct msgb *msgb)
++{
++      return msgb->len - msgb->data_len;
++}
++static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
++{
++      unsigned char *tmp = msgb->tail;
++      msgb->tail += len;
++      msgb->len += len;
++      return tmp;
++}
++static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
++{
++      msgb->data -= len;
++      msgb->len += len;
++      return msgb->data;
++}
++static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
++{
++      msgb->len -= len;
++      return msgb->data += len;
++}
++static inline int msgb_tailroom(const struct msgb *msgb)
++{
++      return (msgb->data + msgb->data_len) - msgb->tail;
++}
++
++/* increase the headroom of an empty msgb, reducing the tailroom */
++static inline void msgb_reserve(struct msgb *msg, int len)
++{
++      msg->data += len;
++      msg->tail += len;
++}
++
++static inline struct msgb *msgb_alloc_headroom(int size, int headroom,
++                                              const char *name)
++{
++      struct msgb *msg = msgb_alloc(size, name);
++      if (msg)
++              msgb_reserve(msg, headroom);
++      return msg;
++}
++
++#endif /* _MSGB_H */
index 0000000,0000000..6d8883e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++osmocore_proto_HEADERS = gsm_04_08.h gsm_04_11.h gsm_04_80.h gsm_08_58.h gsm_12_21.h
++
++osmocore_protodir = $(includedir)/osmocore/protocol
index 0000000,0000000..801b9b5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,743 @@@
++#ifndef PROTO_GSM_04_08_H
++#define PROTO_GSM_04_08_H
++
++#include <stdint.h>
++
++/* GSM TS 04.08  definitions */
++struct gsm_lchan;
++
++struct gsm48_classmark1 {
++      uint8_t spare:1,
++               rev_level:2,
++               es_ind:1,
++               a5_1:1,
++               pwr_lev:3;
++} __attribute__ ((packed));
++
++/* Chapter 10.5.2.5 */
++struct gsm48_chan_desc {
++      uint8_t chan_nr;
++      union {
++              struct {
++                      uint8_t maio_high:4,
++                               h:1,
++                               tsc:3;
++                      uint8_t hsn:6,
++                               maio_low:2;
++              } h1;
++              struct {
++                      uint8_t arfcn_high:2,
++                               spare:2,
++                               h:1,
++                               tsc:3;
++                      uint8_t arfcn_low;
++              } h0;
++      };
++} __attribute__ ((packed));
++
++/* Chapter 10.5.2.21aa */
++struct gsm48_multi_rate_conf {
++      uint8_t smod : 2,
++               spare: 1,
++               icmi : 1,
++               nscb : 1,
++               ver : 3;
++      uint8_t m4_75 : 1,
++               m5_15 : 1,
++               m5_90 : 1,
++               m6_70 : 1,
++               m7_40 : 1,
++               m7_95 : 1,
++               m10_2 : 1,
++               m12_2 : 1;
++} __attribute__((packed));
++
++/* Chapter 10.5.2.30 */
++struct gsm48_req_ref {
++      uint8_t ra;
++      uint8_t t3_high:3,
++               t1_:5;
++      uint8_t t2:5,
++               t3_low:3;
++} __attribute__ ((packed));
++
++/*
++ * Chapter 9.1.5/9.1.6
++ *
++ * For 9.1.6 the chan_desc has the meaning of 10.5.2.5a
++ */
++struct gsm48_chan_mode_modify {
++      struct gsm48_chan_desc chan_desc;
++      uint8_t mode;
++} __attribute__ ((packed));
++
++enum gsm48_chan_mode {
++      GSM48_CMODE_SIGN        = 0x00,
++      GSM48_CMODE_SPEECH_V1   = 0x01,
++      GSM48_CMODE_SPEECH_EFR  = 0x21,
++      GSM48_CMODE_SPEECH_AMR  = 0x41,
++      GSM48_CMODE_DATA_14k5   = 0x0f,
++      GSM48_CMODE_DATA_12k0   = 0x03,
++      GSM48_CMODE_DATA_6k0    = 0x0b,
++      GSM48_CMODE_DATA_3k6    = 0x23,
++};
++
++/* Chapter 9.1.2 */
++struct gsm48_ass_cmd {
++      /* Semantic is from 10.5.2.5a */
++      struct gsm48_chan_desc chan_desc;
++      uint8_t power_command;
++      uint8_t data[0];
++} __attribute__((packed));
++
++/* Chapter 10.5.2.2 */
++struct gsm48_cell_desc {
++      uint8_t bcc:3,
++               ncc:3,
++               arfcn_hi:2;
++      uint8_t arfcn_lo;
++} __attribute__((packed));
++
++/* Chapter 9.1.15 */
++struct gsm48_ho_cmd {
++      struct gsm48_cell_desc cell_desc;
++      struct gsm48_chan_desc chan_desc;
++      uint8_t ho_ref;
++      uint8_t power_command;
++      uint8_t data[0];
++} __attribute__((packed));
++
++/* Chapter 9.1.18 */
++struct gsm48_imm_ass {
++      uint8_t l2_plen;
++      uint8_t proto_discr;
++      uint8_t msg_type;
++      uint8_t page_mode;
++      struct gsm48_chan_desc chan_desc;
++      struct gsm48_req_ref req_ref;
++      uint8_t timing_advance;
++      uint8_t mob_alloc_len;
++      uint8_t mob_alloc[0];
++} __attribute__ ((packed));
++
++/* Chapter 10.5.1.3 */
++struct gsm48_loc_area_id {
++      uint8_t digits[3];      /* BCD! */
++      uint16_t lac;
++} __attribute__ ((packed));
++
++/* Section 9.2.2 */
++struct gsm48_auth_req {
++      uint8_t key_seq:4,
++               spare:4;
++      uint8_t rand[16];
++} __attribute__ ((packed));
++
++/* Section 9.2.15 */
++struct gsm48_loc_upd_req {
++      uint8_t type:4,
++               key_seq:4;
++      struct gsm48_loc_area_id lai;
++      struct gsm48_classmark1 classmark1;
++      uint8_t mi_len;
++      uint8_t mi[0];
++} __attribute__ ((packed));
++
++/* Section 10.1 */
++struct gsm48_hdr {
++      uint8_t proto_discr;
++      uint8_t msg_type;
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++/* Section 9.1.3x System information Type header */
++struct gsm48_system_information_type_header {
++      uint8_t l2_plen;
++      uint8_t rr_protocol_discriminator :4,
++              skip_indicator:4; 
++      uint8_t system_information;
++} __attribute__ ((packed));
++
++struct gsm48_rach_control {
++      uint8_t re :1,
++               cell_bar :1,
++               tx_integer :4,
++               max_trans :2;
++      uint8_t t2;
++      uint8_t t3;
++} __attribute__ ((packed));
++
++/* Section 10.5.2.4 Cell Selection Parameters */
++struct gsm48_cell_sel_par {
++      uint8_t ms_txpwr_max_ccch:5,    /* GSM 05.08 MS-TXPWR-MAX-CCCH */
++               cell_resel_hyst:3;     /* GSM 05.08 CELL-RESELECT-HYSTERESIS */
++      uint8_t rxlev_acc_min:6,        /* GSM 05.08 RXLEV-ACCESS-MIN */
++               neci:1,
++               acs:1;
++} __attribute__ ((packed));
++
++/* Section 10.5.2.11 Control Channel Description , Figure 10.5.33 */
++struct gsm48_control_channel_descr {
++      uint8_t ccch_conf :3,
++              bs_ag_blks_res :3,
++              att :1,
++              spare1 :1;
++      uint8_t bs_pa_mfrms : 3,
++              spare2 :5;
++      uint8_t t3212;
++} __attribute__ ((packed));
++
++struct gsm48_cell_options {
++      uint8_t radio_link_timeout:4,
++               dtx:2,
++               pwrc:1,
++               spare:1;
++} __attribute__ ((packed));
++
++/* Section 9.2.9 CM service request */
++struct gsm48_service_request {
++      uint8_t cm_service_type : 4,
++               cipher_key_seq  : 4;
++      /* length + 3 bytes */
++      uint32_t classmark;
++      uint8_t mi_len;
++      uint8_t mi[0];
++      /* optional priority level */
++} __attribute__ ((packed));
++
++/* Section 9.1.31 System information Type 1 */
++struct gsm48_system_information_type_1 {
++      struct gsm48_system_information_type_header header;
++      uint8_t cell_channel_description[16];
++      struct gsm48_rach_control rach_control;
++      uint8_t rest_octets[0]; /* NCH position on the CCCH */
++} __attribute__ ((packed));
++
++/* Section 9.1.32 System information Type 2 */
++struct gsm48_system_information_type_2 {
++      struct gsm48_system_information_type_header header;
++      uint8_t bcch_frequency_list[16];
++      uint8_t ncc_permitted;
++      struct gsm48_rach_control rach_control;
++} __attribute__ ((packed));
++
++/* Section 9.1.35 System information Type 3 */
++struct gsm48_system_information_type_3 {
++      struct gsm48_system_information_type_header header;
++      uint16_t cell_identity;
++      struct gsm48_loc_area_id lai;
++      struct gsm48_control_channel_descr control_channel_desc;
++      struct gsm48_cell_options cell_options;
++      struct gsm48_cell_sel_par cell_sel_par;
++      struct gsm48_rach_control rach_control;
++      uint8_t rest_octets[0];
++} __attribute__ ((packed));
++
++/* Section 9.1.36 System information Type 4 */
++struct gsm48_system_information_type_4 {
++      struct gsm48_system_information_type_header header;
++      struct gsm48_loc_area_id lai;
++      struct gsm48_cell_sel_par cell_sel_par;
++      struct gsm48_rach_control rach_control;
++      /*      optional CBCH conditional CBCH... followed by
++              mandantory SI 4 Reset Octets
++       */
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++/* Section 9.1.37 System information Type 5 */
++struct gsm48_system_information_type_5 {
++      uint8_t rr_protocol_discriminator :4,
++              skip_indicator:4; 
++      uint8_t system_information;
++      uint8_t bcch_frequency_list[16];
++} __attribute__ ((packed));
++
++/* Section 9.1.40 System information Type 6 */
++struct gsm48_system_information_type_6 {
++      uint8_t rr_protocol_discriminator :4,
++              skip_indicator:4; 
++      uint8_t system_information;
++      uint16_t cell_identity;
++      struct gsm48_loc_area_id lai;
++      struct gsm48_cell_options cell_options;
++      uint8_t ncc_permitted;
++      uint8_t rest_octets[0];
++} __attribute__ ((packed));
++
++/* Section 9.1.43a System Information type 13 */
++struct gsm48_system_information_type_13 {
++      struct gsm48_system_information_type_header header;
++      uint8_t rest_octets[0];
++} __attribute__ ((packed));
++
++/* Section 9.2.12 IMSI Detach Indication */
++struct gsm48_imsi_detach_ind {
++      struct gsm48_classmark1 classmark1;
++      uint8_t mi_len;
++      uint8_t mi[0];
++} __attribute__ ((packed));
++
++/* Section 10.2 + GSM 04.07 12.2.3.1.1 */
++#define GSM48_PDISC_GROUP_CC  0x00
++#define GSM48_PDISC_BCAST_CC  0x01
++#define GSM48_PDISC_PDSS1     0x02
++#define GSM48_PDISC_CC                0x03
++#define GSM48_PDISC_PDSS2     0x04
++#define GSM48_PDISC_MM                0x05
++#define GSM48_PDISC_RR                0x06
++#define GSM48_PDISC_MM_GPRS   0x08
++#define GSM48_PDISC_SMS               0x09
++#define GSM48_PDISC_SM_GPRS   0x0a
++#define GSM48_PDISC_NC_SS     0x0b
++#define GSM48_PDISC_LOC               0x0c
++#define GSM48_PDISC_MASK      0x0f
++#define GSM48_PDISC_USSD      0x11
++
++/* Section 10.4 */
++#define GSM48_MT_RR_INIT_REQ          0x3c
++#define GSM48_MT_RR_ADD_ASS           0x3b
++#define GSM48_MT_RR_IMM_ASS           0x3f
++#define GSM48_MT_RR_IMM_ASS_EXT               0x39
++#define GSM48_MT_RR_IMM_ASS_REJ               0x3a
++
++#define GSM48_MT_RR_CIPH_M_CMD                0x35
++#define GSM48_MT_RR_CIPH_M_COMPL      0x32
++
++#define GSM48_MT_RR_CFG_CHG_CMD               0x30
++#define GSM48_MT_RR_CFG_CHG_ACK               0x31
++#define GSM48_MT_RR_CFG_CHG_REJ               0x33
++
++#define GSM48_MT_RR_ASS_CMD           0x2e
++#define GSM48_MT_RR_ASS_COMPL         0x29
++#define GSM48_MT_RR_ASS_FAIL          0x2f
++#define GSM48_MT_RR_HANDO_CMD         0x2b
++#define GSM48_MT_RR_HANDO_COMPL               0x2c
++#define GSM48_MT_RR_HANDO_FAIL                0x28
++#define GSM48_MT_RR_HANDO_INFO                0x2d
++
++#define GSM48_MT_RR_CELL_CHG_ORDER    0x08
++#define GSM48_MT_RR_PDCH_ASS_CMD      0x23
++
++#define GSM48_MT_RR_CHAN_REL          0x0d
++#define GSM48_MT_RR_PART_REL          0x0a
++#define GSM48_MT_RR_PART_REL_COMP     0x0f
++
++#define GSM48_MT_RR_PAG_REQ_1         0x21
++#define GSM48_MT_RR_PAG_REQ_2         0x22
++#define GSM48_MT_RR_PAG_REQ_3         0x24
++#define GSM48_MT_RR_PAG_RESP          0x27
++#define GSM48_MT_RR_NOTIF_NCH         0x20
++#define GSM48_MT_RR_NOTIF_FACCH               0x25
++#define GSM48_MT_RR_NOTIF_RESP                0x26
++
++#define GSM48_MT_RR_SYSINFO_8         0x18
++#define GSM48_MT_RR_SYSINFO_1         0x19
++#define GSM48_MT_RR_SYSINFO_2         0x1a
++#define GSM48_MT_RR_SYSINFO_3         0x1b
++#define GSM48_MT_RR_SYSINFO_4         0x1c
++#define GSM48_MT_RR_SYSINFO_5         0x1d
++#define GSM48_MT_RR_SYSINFO_6         0x1e
++#define GSM48_MT_RR_SYSINFO_7         0x1f
++
++#define GSM48_MT_RR_SYSINFO_2bis      0x02
++#define GSM48_MT_RR_SYSINFO_2ter      0x03
++#define GSM48_MT_RR_SYSINFO_5bis      0x05
++#define GSM48_MT_RR_SYSINFO_5ter      0x06
++#define GSM48_MT_RR_SYSINFO_9         0x04
++#define GSM48_MT_RR_SYSINFO_13                0x00
++
++#define GSM48_MT_RR_SYSINFO_16                0x3d
++#define GSM48_MT_RR_SYSINFO_17                0x3e
++
++#define GSM48_MT_RR_CHAN_MODE_MODIF   0x10
++#define GSM48_MT_RR_STATUS            0x12
++#define GSM48_MT_RR_CHAN_MODE_MODIF_ACK       0x17
++#define GSM48_MT_RR_FREQ_REDEF                0x14
++#define GSM48_MT_RR_MEAS_REP          0x15
++#define GSM48_MT_RR_CLSM_CHG          0x16
++#define GSM48_MT_RR_CLSM_ENQ          0x13
++#define GSM48_MT_RR_EXT_MEAS_REP      0x36
++#define GSM48_MT_RR_EXT_MEAS_REP_ORD  0x37
++#define GSM48_MT_RR_GPRS_SUSP_REQ     0x34
++
++#define GSM48_MT_RR_VGCS_UPL_GRANT    0x08
++#define GSM48_MT_RR_UPLINK_RELEASE    0x0e
++#define GSM48_MT_RR_UPLINK_FREE               0x0c
++#define GSM48_MT_RR_UPLINK_BUSY               0x2a
++#define GSM48_MT_RR_TALKER_IND                0x11
++
++#define GSM48_MT_RR_APP_INFO          0x38
++
++/* Table 10.2/3GPP TS 04.08 */
++#define GSM48_MT_MM_IMSI_DETACH_IND   0x01
++#define GSM48_MT_MM_LOC_UPD_ACCEPT    0x02
++#define GSM48_MT_MM_LOC_UPD_REJECT    0x04
++#define GSM48_MT_MM_LOC_UPD_REQUEST   0x08
++
++#define GSM48_MT_MM_AUTH_REJ          0x11
++#define GSM48_MT_MM_AUTH_REQ          0x12
++#define GSM48_MT_MM_AUTH_RESP         0x14
++#define GSM48_MT_MM_ID_REQ            0x18
++#define GSM48_MT_MM_ID_RESP           0x19
++#define GSM48_MT_MM_TMSI_REALL_CMD    0x1a
++#define GSM48_MT_MM_TMSI_REALL_COMPL  0x1b
++
++#define GSM48_MT_MM_CM_SERV_ACC               0x21
++#define GSM48_MT_MM_CM_SERV_REJ               0x22
++#define GSM48_MT_MM_CM_SERV_ABORT     0x23
++#define GSM48_MT_MM_CM_SERV_REQ               0x24
++#define GSM48_MT_MM_CM_SERV_PROMPT    0x25
++#define GSM48_MT_MM_CM_REEST_REQ      0x28
++#define GSM48_MT_MM_ABORT             0x29
++
++#define GSM48_MT_MM_NULL              0x30
++#define GSM48_MT_MM_STATUS            0x31
++#define GSM48_MT_MM_INFO              0x32
++
++/* Table 10.3/3GPP TS 04.08 */
++#define GSM48_MT_CC_ALERTING          0x01
++#define GSM48_MT_CC_CALL_CONF         0x08
++#define GSM48_MT_CC_CALL_PROC         0x02
++#define GSM48_MT_CC_CONNECT           0x07
++#define GSM48_MT_CC_CONNECT_ACK               0x0f
++#define GSM48_MT_CC_EMERG_SETUP               0x0e
++#define GSM48_MT_CC_PROGRESS          0x03
++#define GSM48_MT_CC_ESTAB             0x04
++#define GSM48_MT_CC_ESTAB_CONF                0x06
++#define GSM48_MT_CC_RECALL            0x0b
++#define GSM48_MT_CC_START_CC          0x09
++#define GSM48_MT_CC_SETUP             0x05
++
++#define GSM48_MT_CC_MODIFY            0x17
++#define GSM48_MT_CC_MODIFY_COMPL      0x1f
++#define GSM48_MT_CC_MODIFY_REJECT     0x13
++#define GSM48_MT_CC_USER_INFO         0x10
++#define GSM48_MT_CC_HOLD              0x18
++#define GSM48_MT_CC_HOLD_ACK          0x19
++#define GSM48_MT_CC_HOLD_REJ          0x1a
++#define GSM48_MT_CC_RETR              0x1c
++#define GSM48_MT_CC_RETR_ACK          0x1d
++#define GSM48_MT_CC_RETR_REJ          0x1e
++
++#define GSM48_MT_CC_DISCONNECT                0x25
++#define GSM48_MT_CC_RELEASE           0x2d
++#define GSM48_MT_CC_RELEASE_COMPL     0x2a
++
++#define GSM48_MT_CC_CONG_CTRL         0x39
++#define GSM48_MT_CC_NOTIFY            0x3e
++#define GSM48_MT_CC_STATUS            0x3d
++#define GSM48_MT_CC_STATUS_ENQ                0x34
++#define GSM48_MT_CC_START_DTMF                0x35
++#define GSM48_MT_CC_STOP_DTMF         0x31
++#define GSM48_MT_CC_STOP_DTMF_ACK     0x32
++#define GSM48_MT_CC_START_DTMF_ACK    0x36
++#define GSM48_MT_CC_START_DTMF_REJ    0x37
++#define GSM48_MT_CC_FACILITY          0x3a
++
++/* FIXME: Table 10.4 / 10.4a (GPRS) */
++
++/* Section 10.5.2.26, Table 10.5.64 */
++#define GSM48_PM_MASK         0x03
++#define GSM48_PM_NORMAL               0x00
++#define GSM48_PM_EXTENDED     0x01
++#define GSM48_PM_REORG                0x02
++#define GSM48_PM_SAME         0x03
++
++/* Chapter 10.5.3.5 / Table 10.5.93 */
++#define GSM48_LUPD_NORMAL     0x0
++#define GSM48_LUPD_PERIODIC   0x1
++#define GSM48_LUPD_IMSI_ATT   0x2
++#define GSM48_LUPD_RESERVED   0x3
++
++/* Table 10.5.4 */
++#define GSM_MI_TYPE_MASK      0x07
++#define GSM_MI_TYPE_NONE      0x00
++#define GSM_MI_TYPE_IMSI      0x01
++#define GSM_MI_TYPE_IMEI      0x02
++#define GSM_MI_TYPE_IMEISV    0x03
++#define GSM_MI_TYPE_TMSI      0x04
++#define GSM_MI_ODD            0x08
++
++#define GSM48_IE_MUL_RATE_CFG 0x03    /* 10.5.2.21aa */
++#define GSM48_IE_MOBILE_ID    0x17
++#define GSM48_IE_NAME_LONG    0x43    /* 10.5.3.5a */
++#define GSM48_IE_NAME_SHORT   0x45    /* 10.5.3.5a */
++#define GSM48_IE_UTC          0x46    /* 10.5.3.8 */
++#define GSM48_IE_NET_TIME_TZ  0x47    /* 10.5.3.9 */
++#define GSM48_IE_LSA_IDENT    0x48    /* 10.5.3.11 */
++
++#define GSM48_IE_BEARER_CAP   0x04    /* 10.5.4.5 */
++#define GSM48_IE_CAUSE                0x08    /* 10.5.4.11 */
++#define GSM48_IE_CC_CAP               0x15    /* 10.5.4.5a */
++#define GSM48_IE_ALERT                0x19    /* 10.5.4.26 */
++#define GSM48_IE_FACILITY     0x1c    /* 10.5.4.15 */
++#define GSM48_IE_PROGR_IND    0x1e    /* 10.5.4.21 */
++#define GSM48_IE_AUX_STATUS   0x24    /* 10.5.4.4 */
++#define GSM48_IE_NOTIFY               0x27    /* 10.5.4.20 */
++#define GSM48_IE_KPD_FACILITY 0x2c    /* 10.5.4.17 */
++#define GSM48_IE_SIGNAL               0x34    /* 10.5.4.23 */
++#define GSM48_IE_CONN_BCD     0x4c    /* 10.5.4.13 */
++#define GSM48_IE_CONN_SUB     0x4d    /* 10.5.4.14 */
++#define GSM48_IE_CALLING_BCD  0x5c    /* 10.5.4.9 */
++#define GSM48_IE_CALLING_SUB  0x5d    /* 10.5.4.10 */
++#define GSM48_IE_CALLED_BCD   0x5e    /* 10.5.4.7 */
++#define GSM48_IE_CALLED_SUB   0x6d    /* 10.5.4.8 */
++#define GSM48_IE_REDIR_BCD    0x74    /* 10.5.4.21a */
++#define GSM48_IE_REDIR_SUB    0x75    /* 10.5.4.21b */
++#define GSM48_IE_LOWL_COMPAT  0x7c    /* 10.5.4.18 */
++#define GSM48_IE_HIGHL_COMPAT 0x7d    /* 10.5.4.16 */
++#define GSM48_IE_USER_USER    0x7e    /* 10.5.4.25 */
++#define GSM48_IE_SS_VERS      0x7f    /* 10.5.4.24 */
++#define GSM48_IE_MORE_DATA    0xa0    /* 10.5.4.19 */
++#define GSM48_IE_CLIR_SUPP    0xa1    /* 10.5.4.11a */
++#define GSM48_IE_CLIR_INVOC   0xa2    /* 10.5.4.11b */
++#define GSM48_IE_REV_C_SETUP  0xa3    /* 10.5.4.22a */
++#define GSM48_IE_REPEAT_CIR   0xd1    /* 10.5.4.22 */
++#define GSM48_IE_REPEAT_SEQ   0xd3    /* 10.5.4.22 */
++
++/* Section 10.5.4.11 / Table 10.5.122 */
++#define GSM48_CAUSE_CS_GSM    0x60
++
++/* Section 9.1.2 / Table 9.3 */
++#define GSM48_IE_FRQLIST_AFTER        0x05
++#define GSM48_IE_CELL_CH_DESC 0x62
++#define GSM48_IE_MSLOT_DESC   0x10
++#define GSM48_IE_CHANMODE_1   0x63
++#define GSM48_IE_CHANMODE_2   0x11
++#define GSM48_IE_CHANMODE_3   0x13
++#define GSM48_IE_CHANMODE_4   0x14
++#define GSM48_IE_CHANMODE_5   0x15
++#define GSM48_IE_CHANMODE_6   0x16
++#define GSM48_IE_CHANMODE_7   0x17
++#define GSM48_IE_CHANMODE_8   0x18
++#define GSM48_IE_CHANDESC_2   0x64
++/* FIXME */
++
++/* Section 10.5.4.23 / Table 10.5.130 */
++enum gsm48_signal_val {
++      GSM48_SIGNAL_DIALTONE   = 0x00,
++      GSM48_SIGNAL_RINGBACK   = 0x01,
++      GSM48_SIGNAL_INTERCEPT  = 0x02,
++      GSM48_SIGNAL_NET_CONG   = 0x03,
++      GSM48_SIGNAL_BUSY       = 0x04,
++      GSM48_SIGNAL_CONFIRM    = 0x05,
++      GSM48_SIGNAL_ANSWER     = 0x06,
++      GSM48_SIGNAL_CALL_WAIT  = 0x07,
++      GSM48_SIGNAL_OFF_HOOK   = 0x08,
++      GSM48_SIGNAL_OFF        = 0x3f,
++      GSM48_SIGNAL_ALERT_OFF  = 0x4f,
++};
++
++enum gsm48_cause_loc {
++      GSM48_CAUSE_LOC_USER            = 0x00,
++      GSM48_CAUSE_LOC_PRN_S_LU        = 0x01,
++      GSM48_CAUSE_LOC_PUN_S_LU        = 0x02,
++      GSM48_CAUSE_LOC_TRANS_NET       = 0x03,
++      GSM48_CAUSE_LOC_PUN_S_RU        = 0x04,
++      GSM48_CAUSE_LOC_PRN_S_RU        = 0x05,
++      /* not defined */
++      GSM48_CAUSE_LOC_INN_NET         = 0x07,
++      GSM48_CAUSE_LOC_NET_BEYOND      = 0x0a,
++};
++
++/* Section 10.5.2.31 RR Cause / Table 10.5.70 */
++enum gsm48_rr_cause {
++      GSM48_RR_CAUSE_NORMAL           = 0x00,
++      GSM48_RR_CAUSE_ABNORMAL_UNSPEC  = 0x01,
++      GSM48_RR_CAUSE_ABNORMAL_UNACCT  = 0x02,
++      GSM48_RR_CAUSE_ABNORMAL_TIMER   = 0x03,
++      GSM48_RR_CAUSE_ABNORMAL_NOACT   = 0x04,
++      GSM48_RR_CAUSE_PREMPTIVE_REL    = 0x05,
++      GSM48_RR_CAUSE_HNDOVER_IMP      = 0x06,
++      GSM48_RR_CAUSE_CHAN_MODE_UNACCT = 0x07,
++      GSM48_RR_CAUSE_FREQ_NOT_IMPL    = 0x08,
++      GSM48_RR_CAUSE_CALL_CLEARED     = 0x41,
++      GSM48_RR_CAUSE_SEMANT_INCORR    = 0x5f,
++      GSM48_RR_CAUSE_INVALID_MAND_INF = 0x60,
++      GSM48_RR_CAUSE_MSG_TYPE_N       = 0x61,
++      GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT= 0x62,
++      GSM48_RR_CAUSE_COND_IE_ERROR    = 0x64,
++      GSM48_RR_CAUSE_NO_CELL_ALLOC_A  = 0x65,
++      GSM48_RR_CAUSE_PROT_ERROR_UNSPC = 0x6f,
++};
++
++/* Section 10.5.4.11 CC Cause / Table 10.5.123 */
++enum gsm48_cc_cause {
++      GSM48_CC_CAUSE_UNASSIGNED_NR    = 1,
++      GSM48_CC_CAUSE_NO_ROUTE         = 3,
++      GSM48_CC_CAUSE_CHAN_UNACCEPT    = 6,
++      GSM48_CC_CAUSE_OP_DET_BARRING   = 8,
++      GSM48_CC_CAUSE_NORM_CALL_CLEAR  = 16,
++      GSM48_CC_CAUSE_USER_BUSY        = 17,
++      GSM48_CC_CAUSE_USER_NOTRESPOND  = 18,
++      GSM48_CC_CAUSE_USER_ALERTING_NA = 19,
++      GSM48_CC_CAUSE_CALL_REJECTED    = 21,
++      GSM48_CC_CAUSE_NUMBER_CHANGED   = 22,
++      GSM48_CC_CAUSE_PRE_EMPTION      = 25,
++      GSM48_CC_CAUSE_NONSE_USER_CLR   = 26,
++      GSM48_CC_CAUSE_DEST_OOO         = 27,
++      GSM48_CC_CAUSE_INV_NR_FORMAT    = 28,
++      GSM48_CC_CAUSE_FACILITY_REJ     = 29,
++      GSM48_CC_CAUSE_RESP_STATUS_INQ  = 30,
++      GSM48_CC_CAUSE_NORMAL_UNSPEC    = 31,
++      GSM48_CC_CAUSE_NO_CIRCUIT_CHAN  = 34,
++      GSM48_CC_CAUSE_NETWORK_OOO      = 38,
++      GSM48_CC_CAUSE_TEMP_FAILURE     = 41,
++      GSM48_CC_CAUSE_SWITCH_CONG      = 42,
++      GSM48_CC_CAUSE_ACC_INF_DISCARD  = 43,
++      GSM48_CC_CAUSE_REQ_CHAN_UNAVAIL = 44,
++      GSM48_CC_CAUSE_RESOURCE_UNAVAIL = 47,
++      GSM48_CC_CAUSE_QOS_UNAVAIL      = 49,
++      GSM48_CC_CAUSE_REQ_FAC_NOT_SUBSC= 50,
++      GSM48_CC_CAUSE_INC_BARRED_CUG   = 55,
++      GSM48_CC_CAUSE_BEARER_CAP_UNAUTH= 57,
++      GSM48_CC_CAUSE_BEARER_CA_UNAVAIL= 58,
++      GSM48_CC_CAUSE_SERV_OPT_UNAVAIL = 63,
++      GSM48_CC_CAUSE_BEARERSERV_UNIMPL= 65,
++      GSM48_CC_CAUSE_ACM_GE_ACM_MAX   = 68,
++      GSM48_CC_CAUSE_REQ_FAC_NOTIMPL  = 69,
++      GSM48_CC_CAUSE_RESTR_BCAP_AVAIL = 70,
++      GSM48_CC_CAUSE_SERV_OPT_UNIMPL  = 79,
++      GSM48_CC_CAUSE_INVAL_TRANS_ID   = 81,
++      GSM48_CC_CAUSE_USER_NOT_IN_CUG  = 87,
++      GSM48_CC_CAUSE_INCOMPAT_DEST    = 88,
++      GSM48_CC_CAUSE_INVAL_TRANS_NET  = 91,
++      GSM48_CC_CAUSE_SEMANTIC_INCORR  = 95,
++      GSM48_CC_CAUSE_INVAL_MAND_INF   = 96,
++      GSM48_CC_CAUSE_MSGTYPE_NOTEXIST = 97,
++      GSM48_CC_CAUSE_MSGTYPE_INCOMPAT = 98,
++      GSM48_CC_CAUSE_IE_NOTEXIST      = 99,
++      GSM48_CC_CAUSE_COND_IE_ERR      = 100,
++      GSM48_CC_CAUSE_MSG_INCOMP_STATE = 101,
++      GSM48_CC_CAUSE_RECOVERY_TIMER   = 102,
++      GSM48_CC_CAUSE_PROTO_ERR        = 111,
++      GSM48_CC_CAUSE_INTERWORKING     = 127,
++};
++
++/* Annex G, GSM specific cause values for mobility management */
++enum gsm48_reject_value {
++      GSM48_REJECT_IMSI_UNKNOWN_IN_HLR        = 2,
++      GSM48_REJECT_ILLEGAL_MS                 = 3,
++      GSM48_REJECT_IMSI_UNKNOWN_IN_VLR        = 4,
++      GSM48_REJECT_IMEI_NOT_ACCEPTED          = 5,
++      GSM48_REJECT_ILLEGAL_ME                 = 6,
++      GSM48_REJECT_PLMN_NOT_ALLOWED           = 11,
++      GSM48_REJECT_LOC_NOT_ALLOWED            = 12,
++      GSM48_REJECT_ROAMING_NOT_ALLOWED        = 13,
++      GSM48_REJECT_NETWORK_FAILURE            = 17,
++      GSM48_REJECT_CONGESTION                 = 22,
++      GSM48_REJECT_SRV_OPT_NOT_SUPPORTED      = 32,
++      GSM48_REJECT_RQD_SRV_OPT_NOT_SUPPORTED  = 33,
++      GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER   = 34,
++      GSM48_REJECT_CALL_CAN_NOT_BE_IDENTIFIED = 38,
++      GSM48_REJECT_INCORRECT_MESSAGE          = 95,
++      GSM48_REJECT_INVALID_MANDANTORY_INF     = 96,
++      GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED   = 97,
++      GSM48_REJECT_MSG_TYPE_NOT_COMPATIBLE    = 98,
++      GSM48_REJECT_INF_ELEME_NOT_IMPLEMENTED  = 99,
++      GSM48_REJECT_CONDTIONAL_IE_ERROR        = 100,
++      GSM48_REJECT_MSG_NOT_COMPATIBLE         = 101,
++      GSM48_REJECT_PROTOCOL_ERROR             = 111,
++
++      /* according to G.6 Additional cause codes for GMM */
++      GSM48_REJECT_GPRS_NOT_ALLOWED           = 7,
++      GSM48_REJECT_SERVICES_NOT_ALLOWED       = 8,
++      GSM48_REJECT_MS_IDENTITY_NOT_DERVIVABLE = 9,
++      GSM48_REJECT_IMPLICITLY_DETACHED        = 10,
++      GSM48_REJECT_GPRS_NOT_ALLOWED_IN_PLMN   = 14,
++      GSM48_REJECT_MSC_TMP_NOT_REACHABLE      = 16,
++};
++
++enum chreq_type {
++      CHREQ_T_EMERG_CALL,
++      CHREQ_T_CALL_REEST_TCH_F,
++      CHREQ_T_CALL_REEST_TCH_H,
++      CHREQ_T_CALL_REEST_TCH_H_DBL,
++      CHREQ_T_SDCCH,
++      CHREQ_T_TCH_F,
++      CHREQ_T_VOICE_CALL_TCH_H,
++      CHREQ_T_DATA_CALL_TCH_H,
++      CHREQ_T_LOCATION_UPD,
++      CHREQ_T_PAG_R_ANY_NECI0,
++      CHREQ_T_PAG_R_ANY_NECI1,
++      CHREQ_T_PAG_R_TCH_F,
++      CHREQ_T_PAG_R_TCH_FH,
++      CHREQ_T_LMU,
++      CHREQ_T_RESERVED_SDCCH,
++      CHREQ_T_RESERVED_IGNORE,
++};
++
++/* Chapter 11.3 */
++#define GSM48_T301    180, 0
++#define GSM48_T303    30, 0
++#define GSM48_T305    30, 0
++#define GSM48_T306    30, 0
++#define GSM48_T308    10, 0
++#define GSM48_T310    180, 0
++#define GSM48_T313    30, 0
++#define GSM48_T323    30, 0
++#define GSM48_T331    30, 0
++#define GSM48_T333    30, 0
++#define GSM48_T334    25, 0 /* min 15 */
++#define GSM48_T338    30, 0
++
++/* Chapter 5.1.2.2 */
++#define       GSM_CSTATE_NULL                 0
++#define       GSM_CSTATE_INITIATED            1
++#define       GSM_CSTATE_MO_CALL_PROC         3
++#define       GSM_CSTATE_CALL_DELIVERED       4
++#define       GSM_CSTATE_CALL_PRESENT         6
++#define       GSM_CSTATE_CALL_RECEIVED        7
++#define       GSM_CSTATE_CONNECT_REQUEST      8
++#define       GSM_CSTATE_MO_TERM_CALL_CONF    9
++#define       GSM_CSTATE_ACTIVE               10
++#define       GSM_CSTATE_DISCONNECT_REQ       12
++#define       GSM_CSTATE_DISCONNECT_IND       12
++#define       GSM_CSTATE_RELEASE_REQ          19
++#define       GSM_CSTATE_MO_ORIG_MODIFY       26
++#define       GSM_CSTATE_MO_TERM_MODIFY       27
++#define       GSM_CSTATE_CONNECT_IND          28
++
++#define SBIT(a) (1 << a)
++#define ALL_STATES 0xffffffff
++
++/* Table 10.5.3/3GPP TS 04.08: Location Area Identification information element */
++#define GSM_LAC_RESERVED_DETACHED       0x0
++#define GSM_LAC_RESERVED_ALL_BTS        0xfffe
++
++/* GSM 04.08 Bearer Capability: Information Transfer Capability */
++enum gsm48_bcap_itcap {
++      GSM48_BCAP_ITCAP_SPEECH         = 0,
++      GSM48_BCAP_ITCAP_UNR_DIG_INF    = 1,
++      GSM48_BCAP_ITCAP_3k1_AUDIO      = 2,
++      GSM48_BCAP_ITCAP_FAX_G3         = 3,
++      GSM48_BCAP_ITCAP_OTHER          = 5,
++      GSM48_BCAP_ITCAP_RESERVED       = 7,
++};
++
++/* GSM 04.08 Bearer Capability: Transfer Mode */
++enum gsm48_bcap_tmod {
++      GSM48_BCAP_TMOD_CIRCUIT         = 0,
++      GSM48_BCAP_TMOD_PACKET          = 1,
++};
++
++/* GSM 04.08 Bearer Capability: Coding Standard */
++enum gsm48_bcap_coding {
++      GSM48_BCAP_CODING_GSM_STD       = 0,
++};
++
++/* GSM 04.08 Bearer Capability: Radio Channel Requirements */
++enum gsm48_bcap_rrq {
++      GSM48_BCAP_RRQ_FR_ONLY  = 1,
++      GSM48_BCAP_RRQ_DUAL_HR  = 2,
++      GSM48_BCAP_RRQ_DUAL_FR  = 3,
++};
++
++
++#define GSM48_TMSI_LEN        5
++#define GSM48_MID_TMSI_LEN    (GSM48_TMSI_LEN + 2)
++#define GSM48_MI_SIZE 32
++
++
++#endif /* PROTO_GSM_04_08_H */
index 0000000,0000000..c6a2b19
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,188 @@@
++#ifndef PROTO_GSM_04_11_H
++#define PROTO_GSM_04_11_H
++
++#include <stdint.h>
++
++/* GSM TS 04.11  definitions */
++
++/* Chapter 5.2.3: SMC-CS states at the network side */
++enum gsm411_cp_state {
++      GSM411_CPS_IDLE                 = 0,
++      GSM411_CPS_MM_CONN_PENDING      = 1,    /* only MT ! */
++      GSM411_CPS_WAIT_CP_ACK          = 2,
++      GSM411_CPS_MM_ESTABLISHED       = 3,
++};
++
++/* Chapter 6.2.2: SMR states at the network side */
++enum gsm411_rp_state {
++      GSM411_RPS_IDLE                 = 0,
++      GSM411_RPS_WAIT_FOR_RP_ACK      = 1,
++      GSM411_RPS_WAIT_TO_TX_RP_ACK    = 3,
++};
++
++/* Chapter 8.1.2 (refers to GSM 04.07 Chapter 11.2.3.1.1 */
++#define GSM411_PDISC_SMS      0x09
++
++/* Chapter 8.1.3 */
++#define GSM411_MT_CP_DATA     0x01
++#define GSM411_MT_CP_ACK      0x04
++#define GSM411_MT_CP_ERROR    0x10
++
++enum gsm411_cp_ie {
++      GSM411_CP_IE_USER_DATA          = 0x01, /* 8.1.4.1 */
++      GSM411_CP_IE_CAUSE              = 0x02, /* 8.1.4.2. */
++};
++
++/* Section 8.1.4.2 / Table 8.2 */
++enum gsm411_cp_cause {
++      GSM411_CP_CAUSE_NET_FAIL        = 17,
++      GSM411_CP_CAUSE_CONGESTION      = 22,
++      GSM411_CP_CAUSE_INV_TRANS_ID    = 81,
++      GSM411_CP_CAUSE_SEMANT_INC_MSG  = 95,
++      GSM411_CP_CAUSE_INV_MAND_INF    = 96,
++      GSM411_CP_CAUSE_MSGTYPE_NOTEXIST= 97,
++      GSM411_CP_CAUSE_MSG_INCOMP_STATE= 98,
++      GSM411_CP_CAUSE_IE_NOTEXIST     = 99,
++      GSM411_CP_CAUSE_PROTOCOL_ERR    = 111,
++};
++
++/* Chapter 8.2.2 */
++#define GSM411_MT_RP_DATA_MO  0x00
++#define GSM411_MT_RP_DATA_MT  0x01
++#define GSM411_MT_RP_ACK_MO   0x02
++#define GSM411_MT_RP_ACK_MT   0x03
++#define GSM411_MT_RP_ERROR_MO 0x04
++#define GSM411_MT_RP_ERROR_MT 0x05
++#define GSM411_MT_RP_SMMA_MO  0x06
++
++enum gsm411_rp_ie {
++      GSM411_IE_RP_USER_DATA          = 0x41, /* 8.2.5.3 */
++      GSM411_IE_RP_CAUSE              = 0x42, /* 8.2.5.4 */
++};
++
++/* Chapter 8.2.5.4 Table 8.4 */
++enum gsm411_rp_cause {
++      /* valid only for MO */
++      GSM411_RP_CAUSE_MO_NUM_UNASSIGNED       = 1,
++      GSM411_RP_CAUSE_MO_OP_DET_BARR          = 8,
++      GSM411_RP_CAUSE_MO_CALL_BARRED          = 10,
++      GSM411_RP_CAUSE_MO_SMS_REJECTED         = 21,
++      GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER    = 27,
++      GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR  = 28,
++      GSM411_RP_CAUSE_MO_FACILITY_REJ         = 29,
++      GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR       = 30,
++      GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER     = 38,
++      GSM411_RP_CAUSE_MO_TEMP_FAIL            = 41,
++      GSM411_RP_CAUSE_MO_CONGESTION           = 42,
++      GSM411_RP_CAUSE_MO_RES_UNAVAIL          = 47,
++      GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR    = 50,
++      GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL      = 69,
++      GSM411_RP_CAUSE_MO_INTERWORKING         = 127,
++      /* valid only for MT */
++      GSM411_RP_CAUSE_MT_MEM_EXCEEDED         = 22,
++      /* valid for both directions */
++      GSM411_RP_CAUSE_INV_TRANS_REF           = 81,
++      GSM411_RP_CAUSE_SEMANT_INC_MSG          = 95,
++      GSM411_RP_CAUSE_INV_MAND_INF            = 96,
++      GSM411_RP_CAUSE_MSGTYPE_NOTEXIST        = 97,
++      GSM411_RP_CAUSE_MSG_INCOMP_STATE        = 98,
++      GSM411_RP_CAUSE_IE_NOTEXIST             = 99,
++      GSM411_RP_CAUSE_PROTOCOL_ERR            = 111,
++};
++
++/* Chapter 10: Timers */
++#define GSM411_TMR_TR1M               40, 0   /* 35 < x < 45 seconds */
++#define GSM411_TMR_TRAM               30, 0   /* 25 < x < 35 seconds */
++#define GSM411_TMR_TR2M               15, 0   /* 12 < x < 20 seconds */
++
++#define GSM411_TMR_TC1A               30, 0
++
++/* Chapter 8.2.1 */
++struct gsm411_rp_hdr {
++      uint8_t len;
++      uint8_t msg_type;
++      uint8_t msg_ref;
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++/* our own enum, not related to on-air protocol */
++enum sms_alphabet {
++      DCS_NONE,
++      DCS_7BIT_DEFAULT,
++      DCS_UCS2,
++      DCS_8BIT_DATA,
++};
++
++/* GSM 03.40 / Chapter 9.2.3.1: TP-Message-Type-Indicator */
++#define GSM340_SMS_DELIVER_SC2MS      0x00
++#define GSM340_SMS_DELIVER_REP_MS2SC  0x00
++#define GSM340_SMS_STATUS_REP_SC2MS   0x02
++#define GSM340_SMS_COMMAND_MS2SC      0x02
++#define GSM340_SMS_SUBMIT_MS2SC               0x01
++#define GSM340_SMS_SUBMIT_REP_SC2MS   0x01
++#define GSM340_SMS_RESSERVED          0x03
++
++/* GSM 03.40 / Chapter 9.2.3.2: TP-More-Messages-to-Send */
++#define GSM340_TP_MMS_MORE            0
++#define GSM340_TP_MMS_NO_MORE         1
++
++/* GSM 03.40 / Chapter 9.2.3.3: TP-Validity-Period-Format */
++#define GSM340_TP_VPF_NONE            0
++#define GSM340_TP_VPF_RELATIVE                2
++#define GSM340_TP_VPF_ENHANCED                1
++#define GSM340_TP_VPF_ABSOLUTE                3
++
++/* GSM 03.40 / Chapter 9.2.3.4: TP-Status-Report-Indication */
++#define GSM340_TP_SRI_NONE            0
++#define GSM340_TP_SRI_PRESENT         1
++
++/* GSM 03.40 / Chapter 9.2.3.5: TP-Status-Report-Request */
++#define GSM340_TP_SRR_NONE            0
++#define GSM340_TP_SRR_REQUESTED               1
++
++/* GSM 03.40 / Chapter 9.2.3.9: TP-Protocol-Identifier */
++/* telematic interworking (001 or 111 in bits 7-5) */
++#define GSM340_TP_PID_IMPLICIT                0x00
++#define GSM340_TP_PID_TELEX           0x01
++#define GSM340_TP_PID_FAX_G3          0x02
++#define GSM340_TP_PID_FAX_G4          0x03
++#define GSM340_TP_PID_VOICE           0x04
++#define GSM430_TP_PID_ERMES           0x05
++#define GSM430_TP_PID_NATIONAL_PAGING 0x06
++#define GSM430_TP_PID_VIDEOTEX                0x07
++#define GSM430_TP_PID_TELETEX_UNSPEC  0x08
++#define GSM430_TP_PID_TELETEX_PSPDN   0x09
++#define GSM430_TP_PID_TELETEX_CSPDN   0x0a
++#define GSM430_TP_PID_TELETEX_PSTN    0x0b
++#define GSM430_TP_PID_TELETEX_ISDN    0x0c
++#define GSM430_TP_PID_TELETEX_UCI     0x0d
++#define GSM430_TP_PID_MSG_HANDLING    0x10
++#define GSM430_TP_PID_MSG_X400                0x11
++#define GSM430_TP_PID_EMAIL           0x12
++#define GSM430_TP_PID_GSM_MS          0x1f
++/* if bit 7 = 0 and bit 6 = 1 */
++#define GSM430_TP_PID_SMS_TYPE_0      0
++#define GSM430_TP_PID_SMS_TYPE_1      1
++#define GSM430_TP_PID_SMS_TYPE_2      2
++#define GSM430_TP_PID_SMS_TYPE_3      3
++#define GSM430_TP_PID_SMS_TYPE_4      4
++#define GSM430_TP_PID_SMS_TYPE_5      5
++#define GSM430_TP_PID_SMS_TYPE_6      6
++#define GSM430_TP_PID_SMS_TYPE_7      7
++#define GSM430_TP_PID_RETURN_CALL_MSG 0x1f
++#define GSM430_TP_PID_ME_DATA_DNLOAD  0x3d
++#define GSM430_TP_PID_ME_DE_PERSONAL  0x3e
++#define GSM430_TP_PID_ME_SIM_DNLOAD   0x3f
++
++/* GSM 03.38 Chapter 4: SMS Data Coding Scheme */
++#define GSM338_DCS_00_
++
++#define GSM338_DCS_1110_7BIT          (0 << 2)
++#define GSM338_DCS_1111_7BIT          (0 << 2)
++#define GSM338_DCS_1111_8BIT_DATA     (1 << 2)
++#define GSM338_DCS_1111_CLASS0                0
++#define GSM338_DCS_1111_CLASS1_ME     1
++#define GSM338_DCS_1111_CLASS2_SIM    2
++#define GSM338_DCS_1111_CLASS3_TE     3       /* See TS 07.05 */
++
++#endif /* PROTO_GSM_04_11_H */
index 0000000,0000000..fa5c945
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,126 @@@
++#ifndef PROTO_GSM_04_80_H
++#define PROTO_GSM_04_80_H
++
++/* GSM TS 04.80  definitions (Supplementary Services Specification, Formats and Coding) */
++
++/* Section 3.4 */
++#define GSM0480_MTYPE_RELEASE_COMPLETE        0x2A
++#define GSM0480_MTYPE_FACILITY                        0x3A
++#define GSM0480_MTYPE_REGISTER                        0x3B
++
++/* Section 3.5 */
++#define GSM0480_IE_FACILITY                   0x1C
++#define GSM0480_IE_SS_VERSION                 0x7F
++
++/* Section 3.6.2 */
++#define GSM0480_CTYPE_INVOKE                  0xA1
++#define GSM0480_CTYPE_RETURN_RESULT           0xA2
++#define GSM0480_CTYPE_RETURN_ERROR            0xA3
++#define GSM0480_CTYPE_REJECT                  0xA4
++
++/* Section 3.6.3 */
++#define GSM0480_COMPIDTAG_INVOKE_ID           0x02
++#define GSM0480_COMPIDTAG_LINKED_ID           0x80
++
++/* Section 3.6.4 */
++#define GSM0480_OPERATION_CODE                        0x02
++
++/* Section 3.6.5 */
++#define GSM_0480_SEQUENCE_TAG                 0x30
++#define GSM_0480_SET_TAG                      0x31
++
++/* Section 3.6.6 */
++#define GSM_0480_ERROR_CODE_TAG                       0x02
++
++/* Section 3.6.7 */
++/* Table 3.13 */
++#define GSM_0480_PROBLEM_CODE_TAG_GENERAL     0x80
++#define GSM_0480_PROBLEM_CODE_TAG_INVOKE      0x81
++#define GSM_0480_PROBLEM_CODE_TAG_RETURN_RESULT       0x82
++#define GSM_0480_PROBLEM_CODE_TAG_RETURN_ERROR        0x83
++
++/* Table 3.14 */
++#define GSM_0480_GEN_PROB_CODE_UNRECOGNISED   0x00
++#define GSM_0480_GEN_PROB_CODE_MISTYPED               0x01
++#define GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE  0x02
++
++/* Table 3.15 */
++#define GSM_0480_INVOKE_PROB_CODE_DUPLICATE_INVOKE_ID         0x00
++#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION      0x01
++#define GSM_0480_INVOKE_PROB_CODE_MISTYPED_PARAMETER          0x02
++#define GSM_0480_INVOKE_PROB_CODE_RESOURCE_LIMITATION         0x03
++#define GSM_0480_INVOKE_PROB_CODE_INITIATING_RELEASE          0x04
++#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_LINKED_ID      0x05
++#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_RESPONSE  0x06
++#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_OPERATION 0x07
++
++/* Table 3.16 */
++#define GSM_0480_RESULT_PROB_CODE_UNRECOGNISED_INVOKE_ID      0x00
++#define GSM_0480_RESULT_PROB_CODE_RETURN_RESULT_UNEXPECTED    0x01
++#define GSM_0480_RESULT_PROB_CODE_MISTYPED_PARAMETER          0x02
++
++/* Table 3.17 */
++#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_INVOKE_ID               0x00
++#define GSM_0480_ERROR_PROB_CODE_RETURN_ERROR_UNEXPECTED      0x01
++#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_ERROR           0x02
++#define GSM_0480_ERROR_PROB_CODE_UNEXPECTED_ERROR             0x03
++#define GSM_0480_ERROR_PROB_CODE_MISTYPED_PARAMETER           0x04
++
++/* Section 4.5 */
++#define GSM0480_OP_CODE_REGISTER_SS           0x0A
++#define GSM0480_OP_CODE_ERASE_SS              0x0B
++#define GSM0480_OP_CODE_ACTIVATE_SS           0x0C
++#define GSM0480_OP_CODE_DEACTIVATE_SS         0x0D
++#define GSM0480_OP_CODE_INTERROGATE_SS                0x0E
++#define GSM0480_OP_CODE_NOTIFY_SS             0x10
++#define GSM0480_OP_CODE_REGISTER_PASSWORD     0x11
++#define GSM0480_OP_CODE_GET_PASSWORD          0x12
++#define GSM0480_OP_CODE_PROCESS_USS_DATA      0x13
++#define GSM0480_OP_CODE_FORWARD_CHECK_SS_IND  0x26
++#define GSM0480_OP_CODE_PROCESS_USS_REQ               0x3B
++#define GSM0480_OP_CODE_USS_REQUEST           0x3C
++#define GSM0480_OP_CODE_USS_NOTIFY            0x3D
++#define GSM0480_OP_CODE_FORWARD_CUG_INFO      0x78
++#define GSM0480_OP_CODE_SPLIT_MPTY            0x79
++#define GSM0480_OP_CODE_RETRIEVE_MPTY         0x7A
++#define GSM0480_OP_CODE_HOLD_MPTY             0x7B
++#define GSM0480_OP_CODE_BUILD_MPTY            0x7C
++#define GSM0480_OP_CODE_FORWARD_CHARGE_ADVICE 0x7D
++
++#define GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER                   0x01
++#define GSM0480_ERR_CODE_ILLEGAL_SUBSCRIBER                   0x09
++#define GSM0480_ERR_CODE_BEARER_SERVICE_NOT_PROVISIONED               0x0A
++#define GSM0480_ERR_CODE_TELESERVICE_NOT_PROVISIONED          0x0B
++#define GSM0480_ERR_CODE_ILLEGAL_EQUIPMENT                    0x0C
++#define GSM0480_ERR_CODE_CALL_BARRED                          0x0D
++#define GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION                 0x10
++#define GSM0480_ERR_CODE_SS_ERROR_STATUS                      0x11
++#define GSM0480_ERR_CODE_SS_NOT_AVAILABLE                     0x12
++#define GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION            0x13
++#define GSM0480_ERR_CODE_SS_INCOMPATIBILITY                   0x14
++#define GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED                       0x15
++#define GSM0480_ERR_CODE_ABSENT_SUBSCRIBER                    0x1B
++#define GSM0480_ERR_CODE_SYSTEM_FAILURE                               0x22
++#define GSM0480_ERR_CODE_DATA_MISSING                         0x23
++#define GSM0480_ERR_CODE_UNEXPECTED_DATA_VALUE                        0x24
++#define GSM0480_ERR_CODE_PW_REGISTRATION_FAILURE              0x25
++#define GSM0480_ERR_CODE_NEGATIVE_PW_CHECK                    0x26
++#define GSM0480_ERR_CODE_NUM_PW_ATTEMPTS_VIOLATION            0x2B
++#define GSM0480_ERR_CODE_UNKNOWN_ALPHABET                     0x47
++#define GSM0480_ERR_CODE_USSD_BUSY                            0x48
++#define GSM0480_ERR_CODE_MAX_MPTY_PARTICIPANTS                        0x7E
++#define GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE              0x7F
++
++/* ASN.1 type-tags */
++#define ASN1_BOOLEAN_TAG              0x01
++#define ASN1_INTEGER_TAG              0x02
++#define ASN1_BIT_STRING_TAG           0x03
++#define ASN1_OCTET_STRING_TAG         0x04
++#define ASN1_NULL_TYPE_TAG            0x05
++#define ASN1_OBJECT_ID_TAG            0x06
++#define ASN1_UTF8_STRING_TAG          0x0C
++#define ASN1_PRINTABLE_STRING_TAG     0x13
++#define ASN1_IA5_STRING_TAG           0x16
++#define ASN1_UNICODE_STRING_TAG               0x1E
++
++#endif /* PROTO_GSM_04_80_H */
index 0000000,0000000..ca9398f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,512 @@@
++#ifndef PROTO_GSM_08_58_H
++#define PROTO_GSM_08_58_H
++
++/* GSM Radio Signalling Link messages on the A-bis interface 
++ * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
++
++/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <stdint.h>
++
++struct abis_rsl_common_hdr {
++      uint8_t msg_discr;
++      uint8_t msg_type;
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++/* Chapter 8.3 */
++struct abis_rsl_rll_hdr {
++      struct abis_rsl_common_hdr c;
++      uint8_t ie_chan;
++      uint8_t chan_nr;
++      uint8_t ie_link_id;
++      uint8_t link_id;
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++/* Chapter 8.3 and 8.4 */
++struct abis_rsl_dchan_hdr {
++      struct abis_rsl_common_hdr c;
++      uint8_t ie_chan;
++      uint8_t chan_nr;
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++
++/* Chapter 9.1 */
++#define ABIS_RSL_MDISC_RLL            0x02
++#define ABIS_RSL_MDISC_DED_CHAN               0x08
++#define ABIS_RSL_MDISC_COM_CHAN               0x0c
++#define ABIS_RSL_MDISC_TRX            0x10
++#define ABIS_RSL_MDISC_LOC            0x20
++#define ABIS_RSL_MDISC_IPACCESS               0x7e
++#define ABIS_RSL_MDISC_TRANSP         0x01
++
++#define ABIS_RSL_MDISC_IS_TRANSP(x)   (x & 0x01)
++
++/* Chapter 9.1 */
++enum abis_rsl_msgtype {
++      /* Radio Link Layer Management */
++      RSL_MT_DATA_REQ                 = 0x01,
++      RSL_MT_DATA_IND,
++      RSL_MT_ERROR_IND,
++      RSL_MT_EST_REQ,
++      RSL_MT_EST_CONF,
++      RSL_MT_EST_IND,
++      RSL_MT_REL_REQ,
++      RSL_MT_REL_CONF,
++      RSL_MT_REL_IND,
++      RSL_MT_UNIT_DATA_REQ,
++      RSL_MT_UNIT_DATA_IND,           /* 0x0b */
++
++      /* Common Channel Management / TRX Management */
++      RSL_MT_BCCH_INFO                        = 0x11,
++      RSL_MT_CCCH_LOAD_IND,
++      RSL_MT_CHAN_RQD,
++      RSL_MT_DELETE_IND,
++      RSL_MT_PAGING_CMD,
++      RSL_MT_IMMEDIATE_ASSIGN_CMD,
++      RSL_MT_SMS_BC_REQ,
++      /* empty */
++      RSL_MT_RF_RES_IND                       = 0x19,
++      RSL_MT_SACCH_FILL,
++      RSL_MT_OVERLOAD,
++      RSL_MT_ERROR_REPORT,
++      RSL_MT_SMS_BC_CMD,
++      RSL_MT_CBCH_LOAD_IND,
++      RSL_MT_NOT_CMD,                 /* 0x1f */
++
++      /* Dedicate Channel Management */
++      RSL_MT_CHAN_ACTIV                       = 0x21,
++      RSL_MT_CHAN_ACTIV_ACK,
++      RSL_MT_CHAN_ACTIV_NACK,
++      RSL_MT_CONN_FAIL,
++      RSL_MT_DEACTIVATE_SACCH,
++      RSL_MT_ENCR_CMD,
++      RSL_MT_HANDO_DET,
++      RSL_MT_MEAS_RES,
++      RSL_MT_MODE_MODIFY_REQ,
++      RSL_MT_MODE_MODIFY_ACK,
++      RSL_MT_MODE_MODIFY_NACK,
++      RSL_MT_PHY_CONTEXT_REQ,
++      RSL_MT_PHY_CONTEXT_CONF,
++      RSL_MT_RF_CHAN_REL,
++      RSL_MT_MS_POWER_CONTROL,
++      RSL_MT_BS_POWER_CONTROL,                /* 0x30 */
++      RSL_MT_PREPROC_CONFIG,
++      RSL_MT_PREPROC_MEAS_RES,
++      RSL_MT_RF_CHAN_REL_ACK,
++      RSL_MT_SACCH_INFO_MODIFY,
++      RSL_MT_TALKER_DET,
++      RSL_MT_LISTENER_DET,
++      RSL_MT_REMOTE_CODEC_CONF_REP,
++      RSL_MT_RTD_REP,
++      RSL_MT_PRE_HANDO_NOTIF,
++      RSL_MT_MR_CODEC_MOD_REQ,
++      RSL_MT_MR_CODEC_MOD_ACK,
++      RSL_MT_MR_CODEC_MOD_NACK,
++      RSL_MT_MR_CODEC_MOD_PER,
++      RSL_MT_TFO_REP,
++      RSL_MT_TFO_MOD_REQ,             /* 0x3f */
++      RSL_MT_LOCATION_INFO            = 0x41,
++
++      /* ip.access specific RSL message types */
++      RSL_MT_IPAC_DIR_RETR_ENQ        = 0x40,
++      RSL_MT_IPAC_PDCH_ACT            = 0x48,
++      RSL_MT_IPAC_PDCH_ACT_ACK,
++      RSL_MT_IPAC_PDCH_ACT_NACK,
++      RSL_MT_IPAC_PDCH_DEACT          = 0x4b,
++      RSL_MT_IPAC_PDCH_DEACT_ACK,
++      RSL_MT_IPAC_PDCH_DEACT_NACK,
++      RSL_MT_IPAC_CONNECT_MUX         = 0x50,
++      RSL_MT_IPAC_CONNECT_MUX_ACK,
++      RSL_MT_IPAC_CONNECT_MUX_NACK,
++      RSL_MT_IPAC_BIND_MUX            = 0x53,
++      RSL_MT_IPAC_BIND_MUX_ACK,
++      RSL_MT_IPAC_BIND_MUX_NACK,
++      RSL_MT_IPAC_DISC_MUX            = 0x56,
++      RSL_MT_IPAC_DISC_MUX_ACK,
++      RSL_MT_IPAC_DISC_MUX_NACK,
++      RSL_MT_IPAC_CRCX                = 0x70,         /* Bind to local BTS RTP port */
++      RSL_MT_IPAC_CRCX_ACK,
++      RSL_MT_IPAC_CRCX_NACK,
++      RSL_MT_IPAC_MDCX                = 0x73,
++      RSL_MT_IPAC_MDCX_ACK,
++      RSL_MT_IPAC_MDCX_NACK,
++      RSL_MT_IPAC_DLCX_IND            = 0x76,
++      RSL_MT_IPAC_DLCX                = 0x77,
++      RSL_MT_IPAC_DLCX_ACK,
++      RSL_MT_IPAC_DLCX_NACK,
++};
++
++/* Siemens vendor-specific */
++enum abis_rsl_msgtype_siemens {
++      RSL_MT_SIEMENS_MRPCI            = 0x41,
++      RSL_MT_SIEMENS_INTRAC_HO_COND_IND = 0x42,
++      RSL_MT_SIEMENS_INTERC_HO_COND_IND = 0x43,
++      RSL_MT_SIEMENS_FORCED_HO_REQ    = 0x44,
++      RSL_MT_SIEMENS_PREF_AREA_REQ    = 0x45,
++      RSL_MT_SIEMENS_PREF_AREA        = 0x46,
++      RSL_MT_SIEMENS_START_TRACE      = 0x47,
++      RSL_MT_SIEMENS_START_TRACE_ACK  = 0x48,
++      RSL_MT_SIEMENS_STOP_TRACE       = 0x49,
++      RSL_MT_SIEMENS_TRMR             = 0x4a,
++      RSL_MT_SIEMENS_HO_FAIL_IND      = 0x4b,
++      RSL_MT_SIEMENS_STOP_TRACE_ACK   = 0x4c,
++      RSL_MT_SIEMENS_UPLF             = 0x4d,
++      RSL_MT_SIEMENS_UPLB             = 0x4e,
++      RSL_MT_SIEMENS_SET_SYS_INFO_10  = 0x4f,
++      RSL_MT_SIEMENS_MODIF_COND_IND   = 0x50,
++};
++
++/* Chapter 9.3 */
++enum abis_rsl_ie {
++      RSL_IE_CHAN_NR                  = 0x01,
++      RSL_IE_LINK_IDENT,
++      RSL_IE_ACT_TYPE,
++      RSL_IE_BS_POWER,
++      RSL_IE_CHAN_IDENT,
++      RSL_IE_CHAN_MODE,
++      RSL_IE_ENCR_INFO,
++      RSL_IE_FRAME_NUMBER,
++      RSL_IE_HANDO_REF,
++      RSL_IE_L1_INFO,
++      RSL_IE_L3_INFO,
++      RSL_IE_MS_IDENTITY,
++      RSL_IE_MS_POWER,
++      RSL_IE_PAGING_GROUP,
++      RSL_IE_PAGING_LOAD,
++      RSL_IE_PYHS_CONTEXT             = 0x10,
++      RSL_IE_ACCESS_DELAY,
++      RSL_IE_RACH_LOAD,
++      RSL_IE_REQ_REFERENCE,
++      RSL_IE_RELEASE_MODE,
++      RSL_IE_RESOURCE_INFO,
++      RSL_IE_RLM_CAUSE,
++      RSL_IE_STARTNG_TIME,
++      RSL_IE_TIMING_ADVANCE,
++      RSL_IE_UPLINK_MEAS,
++      RSL_IE_CAUSE,
++      RSL_IE_MEAS_RES_NR,
++      RSL_IE_MSG_ID,
++      /* reserved */
++      RSL_IE_SYSINFO_TYPE             = 0x1e,
++      RSL_IE_MS_POWER_PARAM,
++      RSL_IE_BS_POWER_PARAM,
++      RSL_IE_PREPROC_PARAM,
++      RSL_IE_PREPROC_MEAS,
++      RSL_IE_IMM_ASS_INFO,            /* Phase 1 (3.6.0), later Full below */
++      RSL_IE_SMSCB_INFO               = 0x24,
++      RSL_IE_MS_TIMING_OFFSET,
++      RSL_IE_ERR_MSG,
++      RSL_IE_FULL_BCCH_INFO,
++      RSL_IE_CHAN_NEEDED,
++      RSL_IE_CB_CMD_TYPE,
++      RSL_IE_SMSCB_MSG,
++      RSL_IE_FULL_IMM_ASS_INFO,
++      RSL_IE_SACCH_INFO,
++      RSL_IE_CBCH_LOAD_INFO,
++      RSL_IE_SMSCB_CHAN_INDICATOR,
++      RSL_IE_GROUP_CALL_REF,
++      RSL_IE_CHAN_DESC                = 0x30,
++      RSL_IE_NCH_DRX_INFO,
++      RSL_IE_CMD_INDICATOR,
++      RSL_IE_EMLPP_PRIO,
++      RSL_IE_UIC,
++      RSL_IE_MAIN_CHAN_REF,
++      RSL_IE_MR_CONFIG,
++      RSL_IE_MR_CONTROL,
++      RSL_IE_SUP_CODEC_TYPES,
++      RSL_IE_CODEC_CONFIG,
++      RSL_IE_RTD,
++      RSL_IE_TFO_STATUS,
++      RSL_IE_LLP_APDU,
++      /* Siemens vendor-specific */
++      RSL_IE_SIEMENS_MRPCI            = 0x40,
++      RSL_IE_SIEMENS_PREF_AREA_TYPE   = 0x43,
++      RSL_IE_SIEMENS_ININ_CELL_HO_PAR = 0x45,
++      RSL_IE_SIEMENS_TRACE_REF_NR     = 0x46,
++      RSL_IE_SIEMENS_INT_TRACE_IDX    = 0x47,
++      RSL_IE_SIEMENS_L2_HDR_INFO      = 0x48,
++      RSL_IE_SIEMENS_HIGHEST_RATE     = 0x4e,
++      RSL_IE_SIEMENS_SUGGESTED_RATE   = 0x4f,
++
++      /* ip.access */
++      RSL_IE_IPAC_SRTP_CONFIG = 0xe0,
++      RSL_IE_IPAC_PROXY_UDP   = 0xe1,
++      RSL_IE_IPAC_BSCMPL_TOUT = 0xe2,
++      RSL_IE_IPAC_REMOTE_IP   = 0xf0,
++      RSL_IE_IPAC_REMOTE_PORT = 0xf1,
++      RSL_IE_IPAC_RTP_PAYLOAD = 0xf2,
++      RSL_IE_IPAC_LOCAL_PORT  = 0xf3,
++      RSL_IE_IPAC_SPEECH_MODE = 0xf4,
++      RSL_IE_IPAC_LOCAL_IP    = 0xf5,
++      RSL_IE_IPAC_CONN_STAT   = 0xf6,
++      RSL_IE_IPAC_HO_C_PARMS  = 0xf7,
++      RSL_IE_IPAC_CONN_ID     = 0xf8,
++      RSL_IE_IPAC_RTP_CSD_FMT = 0xf9,
++      RSL_IE_IPAC_RTP_JIT_BUF = 0xfa,
++      RSL_IE_IPAC_RTP_COMPR   = 0xfb,
++      RSL_IE_IPAC_RTP_PAYLOAD2= 0xfc,
++      RSL_IE_IPAC_RTP_MPLEX   = 0xfd,
++      RSL_IE_IPAC_RTP_MPLEX_ID= 0xfe,
++};
++
++/* Chapter 9.3.1 */
++#define RSL_CHAN_NR_MASK      0xf8
++#define RSL_CHAN_Bm_ACCHs     0x08
++#define RSL_CHAN_Lm_ACCHs     0x10    /* .. 0x18 */
++#define RSL_CHAN_SDCCH4_ACCH  0x20    /* .. 0x38 */
++#define RSL_CHAN_SDCCH8_ACCH  0x40    /* ...0x78 */
++#define RSL_CHAN_BCCH         0x80
++#define RSL_CHAN_RACH         0x88
++#define RSL_CHAN_PCH_AGCH     0x90
++
++/* Chapter 9.3.3 */
++#define RSL_ACT_TYPE_INITIAL  0x00
++#define RSL_ACT_TYPE_REACT    0x80
++#define RSL_ACT_INTRA_IMM_ASS 0x00
++#define RSL_ACT_INTRA_NORM_ASS        0x01
++#define RSL_ACT_INTER_ASYNC   0x02
++#define RSL_ACT_INTER_SYNC    0x03
++#define RSL_ACT_SECOND_ADD    0x04
++#define RSL_ACT_SECOND_MULTI  0x05
++
++/* Chapter 9.3.6 */
++struct rsl_ie_chan_mode {
++      uint8_t dtx_dtu;
++      uint8_t spd_ind;
++      uint8_t chan_rt;
++      uint8_t chan_rate;
++} __attribute__ ((packed));
++#define RSL_CMOD_DTXu         0x01    /* uplink */
++#define RSL_CMOD_DTXd         0x02    /* downlink */
++enum rsl_cmod_spd {
++      RSL_CMOD_SPD_SPEECH     = 0x01,
++      RSL_CMOD_SPD_DATA       = 0x02,
++      RSL_CMOD_SPD_SIGN       = 0x03,
++};
++#define RSL_CMOD_CRT_SDCCH    0x01
++#define RSL_CMOD_CRT_TCH_Bm   0x08    /* full-rate */
++#define RSL_CMOD_CRT_TCH_Lm   0x09    /* half-rate */
++/* FIXME: More CRT types */
++/* Speech */
++#define RSL_CMOD_SP_GSM1      0x01
++#define RSL_CMOD_SP_GSM2      0x11
++#define RSL_CMOD_SP_GSM3      0x21
++/* Data */
++#define RSL_CMOD_SP_NT_14k5   0x58
++#define RSL_CMOD_SP_NT_12k0   0x50
++#define RSL_CMOD_SP_NT_6k0    0x51
++
++/* Chapter 9.3.5 */
++struct rsl_ie_chan_ident {
++      /* GSM 04.08 10.5.2.5 */
++      struct {
++              uint8_t iei;
++              uint8_t chan_nr;        /* enc_chan_nr */
++              uint8_t oct3;
++              uint8_t oct4;
++      } chan_desc;
++#if 0 /* spec says we need this but Abissim doesn't use it */
++      struct {
++              uint8_t tag;
++              uint8_t len;
++      } mobile_alloc;
++#endif
++} __attribute__ ((packed));
++
++/* Chapter 9.3.22 */
++#define RLL_CAUSE_T200_EXPIRED                0x01
++#define RLL_CAUSE_REEST_REQ           0x02
++#define RLL_CAUSE_UNSOL_UA_RESP               0x03
++#define RLL_CAUSE_UNSOL_DM_RESP               0x04
++#define RLL_CAUSE_UNSOL_DM_RESP_MF    0x05
++#define RLL_CAUSE_UNSOL_SPRV_RESP     0x06
++#define RLL_CAUSE_SEQ_ERR             0x07
++#define RLL_CAUSE_UFRM_INC_PARAM      0x08
++#define RLL_CAUSE_SFRM_INC_PARAM      0x09
++#define RLL_CAUSE_IFRM_INC_MBITS      0x0a
++#define RLL_CAUSE_IFRM_INC_LEN                0x0b
++#define RLL_CAUSE_FRM_UNIMPL          0x0c
++#define RLL_CAUSE_SABM_MF             0x0d
++#define RLL_CAUSE_SABM_INFO_NOTALL    0x0e
++
++/* Chapter 9.3.26 */
++#define RSL_ERRCLS_NORMAL             0x00
++#define RSL_ERRCLS_RESOURCE_UNAVAIL   0x20
++#define RSL_ERRCLS_SERVICE_UNAVAIL    0x30
++#define RSL_ERRCLS_SERVICE_UNIMPL     0x40
++#define RSL_ERRCLS_INVAL_MSG          0x50
++#define RSL_ERRCLS_PROTO_ERROR                0x60
++#define RSL_ERRCLS_INTERWORKING               0x70
++
++/* normal event */
++#define RSL_ERR_RADIO_IF_FAIL         0x00
++#define RSL_ERR_RADIO_LINK_FAIL               0x01
++#define RSL_ERR_HANDOVER_ACC_FAIL     0x02
++#define RSL_ERR_TALKER_ACC_FAIL               0x03
++#define RSL_ERR_OM_INTERVENTION               0x07
++#define RSL_ERR_NORMAL_UNSPEC         0x0f
++#define RSL_ERR_T_MSRFPCI_EXP         0x18
++/* resource unavailable */
++#define RSL_ERR_EQUIPMENT_FAIL                0x20
++#define RSL_ERR_RR_UNAVAIL            0x21
++#define RSL_ERR_TERR_CH_FAIL          0x22
++#define RSL_ERR_CCCH_OVERLOAD         0x23
++#define RSL_ERR_ACCH_OVERLOAD         0x24
++#define RSL_ERR_PROCESSOR_OVERLOAD    0x25
++#define RSL_ERR_RES_UNAVAIL           0x2f
++/* service or option not available */
++#define RSL_ERR_TRANSC_UNAVAIL                0x30
++#define RSL_ERR_SERV_OPT_UNAVAIL      0x3f
++/* service or option not implemented */
++#define RSL_ERR_ENCR_UNIMPL           0x40
++#define RSL_ERR_SERV_OPT_UNIMPL               0x4f
++/* invalid message */
++#define RSL_ERR_RCH_ALR_ACTV_ALLOC    0x50
++#define RSL_ERR_INVALID_MESSAGE               0x5f
++/* protocol error */
++#define RSL_ERR_MSG_DISCR             0x60
++#define RSL_ERR_MSG_TYPE              0x61
++#define RSL_ERR_MSG_SEQ                       0x62
++#define RSL_ERR_IE_ERROR              0x63
++#define RSL_ERR_MAND_IE_ERROR         0x64
++#define RSL_ERR_OPT_IE_ERROR          0x65
++#define RSL_ERR_IE_NONEXIST           0x66
++#define RSL_ERR_IE_LENGTH             0x67
++#define RSL_ERR_IE_CONTENT            0x68
++#define RSL_ERR_PROTO                 0x6f
++/* interworking */
++#define RSL_ERR_INTERWORKING          0x7f
++
++/* Chapter 9.3.30 */
++#define RSL_SYSTEM_INFO_8     0x00
++#define RSL_SYSTEM_INFO_1     0x01
++#define RSL_SYSTEM_INFO_2     0x02
++#define RSL_SYSTEM_INFO_3     0x03
++#define RSL_SYSTEM_INFO_4     0x04
++#define RSL_SYSTEM_INFO_5     0x05
++#define RSL_SYSTEM_INFO_6     0x06
++#define RSL_SYSTEM_INFO_7     0x07
++#define RSL_SYSTEM_INFO_16    0x08
++#define RSL_SYSTEM_INFO_17    0x09
++#define RSL_SYSTEM_INFO_2bis  0x0a
++#define RSL_SYSTEM_INFO_2ter  0x0b
++#define RSL_SYSTEM_INFO_5bis  0x0d
++#define RSL_SYSTEM_INFO_5ter  0x0e
++#define RSL_SYSTEM_INFO_10    0x0f
++#define REL_EXT_MEAS_ORDER    0x47
++#define RSL_MEAS_INFO         0x48
++#define RSL_SYSTEM_INFO_13    0x28
++#define RSL_SYSTEM_INFO_2quater       0x29
++#define RSL_SYSTEM_INFO_9     0x2a
++#define RSL_SYSTEM_INFO_18    0x2b
++#define RSL_SYSTEM_INFO_19    0x2c
++#define RSL_SYSTEM_INFO_20    0x2d
++
++/* Chapter 9.3.40 */
++#define RSL_CHANNEED_ANY      0x00
++#define RSL_CHANNEED_SDCCH    0x01
++#define RSL_CHANNEED_TCH_F    0x02
++#define RSL_CHANNEED_TCH_ForH 0x03
++
++/* Chapter 3.3.2.3 Brocast control channel */
++/* CCCH-CONF, NC is not combined */
++#define RSL_BCCH_CCCH_CONF_1_NC       0x00
++#define RSL_BCCH_CCCH_CONF_1_C        0x01
++#define RSL_BCCH_CCCH_CONF_2_NC       0x02
++#define RSL_BCCH_CCCH_CONF_3_NC       0x04
++#define RSL_BCCH_CCCH_CONF_4_NC       0x06
++
++/* BS-PA-MFRMS */
++#define RSL_BS_PA_MFRMS_2     0x00
++#define RSL_BS_PA_MFRMS_3     0x01
++#define RSL_BS_PA_MFRMS_4     0x02
++#define RSL_BS_PA_MFRMS_5     0x03
++#define RSL_BS_PA_MFRMS_6     0x04
++#define RSL_BS_PA_MFRMS_7     0x05
++#define RSL_BS_PA_MFRMS_8     0x06
++#define RSL_BS_PA_MFRMS_9     0x07
++
++/* RSL_IE_IPAC_RTP_PAYLOAD[2] */
++enum rsl_ipac_rtp_payload {
++      RSL_IPAC_RTP_GSM        = 1,
++      RSL_IPAC_RTP_EFR,
++      RSL_IPAC_RTP_AMR,
++      RSL_IPAC_RTP_CSD,
++      RSL_IPAC_RTP_MUX,
++};
++
++/* RSL_IE_IPAC_SPEECH_MODE, lower four bits */
++enum rsl_ipac_speech_mode_s {
++      RSL_IPAC_SPEECH_GSM_FR = 0,     /* GSM FR (Type 1, FS) */
++      RSL_IPAC_SPEECH_GSM_EFR = 1,    /* GSM EFR (Type 2, FS) */
++      RSL_IPAC_SPEECH_GSM_AMR_FR = 2, /* GSM AMR/FR (Type 3, FS) */
++      RSL_IPAC_SPEECH_GSM_HR = 3,     /* GSM HR (Type 1, HS) */
++      RSL_IPAC_SPEECH_GSM_AMR_HR = 5, /* GSM AMR/hr (Type 3, HS) */
++      RSL_IPAC_SPEECH_AS_RTP = 0xf,   /* As specified by RTP Payload IE */
++};
++/* RSL_IE_IPAC_SPEECH_MODE, upper four bits */
++enum rsl_ipac_speech_mode_m {
++      RSL_IPAC_SPEECH_M_RXTX = 0,     /* Send and Receive */
++      RSL_IPAC_SPEECH_M_RX = 1,       /* Receive only */
++      RSL_IPAC_SPEECH_M_TX = 2,       /* Send only */
++};
++
++/* RSL_IE_IPAC_RTP_CSD_FMT, lower four bits */
++enum rsl_ipac_rtp_csd_format_d {
++      RSL_IPAC_RTP_CSD_EXT_TRAU = 0,
++      RSL_IPAC_RTP_CSD_NON_TRAU = 1,
++      RSL_IPAC_RTP_CSD_TRAU_BTS = 2,
++      RSL_IPAC_RTP_CSD_IWF_FREE = 3,
++};
++/* RSL_IE_IPAC_RTP_CSD_FMT, upper four bits */
++enum rsl_ipac_rtp_csd_format_ir {
++      RSL_IPAC_RTP_CSD_IR_8k = 0,
++      RSL_IPAC_RTP_CSD_IR_16k = 1,
++      RSL_IPAC_RTP_CSD_IR_32k = 2,
++      RSL_IPAC_RTP_CSD_IR_64k = 3,
++};
++
++/* Siemens vendor-specific RSL extensions */
++struct rsl_mrpci {
++      uint8_t power_class:3,
++               vgcs_capable:1,
++               vbs_capable:1,
++               gsm_phase:2;
++} __attribute__ ((packed));
++
++enum rsl_mrpci_pwrclass {
++      RSL_MRPCI_PWRC_1        = 0,
++      RSL_MRPCI_PWRC_2        = 1,
++      RSL_MRPCI_PWRC_3        = 2,
++      RSL_MRPCI_PWRC_4        = 3,
++      RSL_MRPCI_PWRC_5        = 4,
++};
++enum rsl_mrpci_phase {
++      RSL_MRPCI_PHASE_1       = 0,
++      /* reserved */
++      RSL_MRPCI_PHASE_2       = 2,
++      RSL_MRPCI_PHASE_2PLUS   = 3,
++};
++
++
++#endif /* PROTO_GSM_08_58_H */
index 0000000,0000000..ac6db4b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,691 @@@
++#ifndef PROTO_GSM_12_21_H
++#define PROTO_GSM_12_21_H
++
++/* GSM Network Management messages on the A-bis interface 
++ * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
++
++/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <stdint.h>
++#include <osmocore/tlv.h>
++
++/* generic header in front of every OML message according to TS 08.59 */
++struct abis_om_hdr {
++      uint8_t mdisc;
++      uint8_t placement;
++      uint8_t sequence;
++      uint8_t length;
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++#define ABIS_OM_MDISC_FOM             0x80
++#define ABIS_OM_MDISC_MMI             0x40
++#define ABIS_OM_MDISC_TRAU            0x20
++#define ABIS_OM_MDISC_MANUF           0x10
++#define ABIS_OM_PLACEMENT_ONLY                0x80
++#define ABIS_OM_PLACEMENT_FIRST       0x40
++#define ABIS_OM_PLACEMENT_MIDDLE      0x20
++#define ABIS_OM_PLACEMENT_LAST                0x10
++
++struct abis_om_obj_inst {
++      uint8_t bts_nr;
++      uint8_t trx_nr;
++      uint8_t ts_nr;
++} __attribute__ ((packed));
++
++struct abis_om_fom_hdr {
++      uint8_t msg_type;
++      uint8_t obj_class;
++      struct abis_om_obj_inst obj_inst;
++      uint8_t data[0];
++} __attribute__ ((packed));
++
++#define ABIS_OM_FOM_HDR_SIZE  (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_fom_hdr))
++
++/* Section 9.1: Message Types */
++enum abis_nm_msgtype {
++      /* SW Download Management Messages */
++      NM_MT_LOAD_INIT                 = 0x01,
++      NM_MT_LOAD_INIT_ACK,
++      NM_MT_LOAD_INIT_NACK,
++      NM_MT_LOAD_SEG,
++      NM_MT_LOAD_SEG_ACK,
++      NM_MT_LOAD_ABORT,
++      NM_MT_LOAD_END,
++      NM_MT_LOAD_END_ACK,
++      NM_MT_LOAD_END_NACK,
++      NM_MT_SW_ACT_REQ,               /* BTS->BSC */
++      NM_MT_SW_ACT_REQ_ACK,
++      NM_MT_SW_ACT_REQ_NACK,
++      NM_MT_ACTIVATE_SW,              /* BSC->BTS */
++      NM_MT_ACTIVATE_SW_ACK,
++      NM_MT_ACTIVATE_SW_NACK,
++      NM_MT_SW_ACTIVATED_REP,         /* 0x10 */
++      /* A-bis Interface Management Messages */
++      NM_MT_ESTABLISH_TEI             = 0x21,
++      NM_MT_ESTABLISH_TEI_ACK,
++      NM_MT_ESTABLISH_TEI_NACK,
++      NM_MT_CONN_TERR_SIGN,
++      NM_MT_CONN_TERR_SIGN_ACK,
++      NM_MT_CONN_TERR_SIGN_NACK,
++      NM_MT_DISC_TERR_SIGN,
++      NM_MT_DISC_TERR_SIGN_ACK,
++      NM_MT_DISC_TERR_SIGN_NACK,
++      NM_MT_CONN_TERR_TRAF,
++      NM_MT_CONN_TERR_TRAF_ACK,
++      NM_MT_CONN_TERR_TRAF_NACK,
++      NM_MT_DISC_TERR_TRAF,
++      NM_MT_DISC_TERR_TRAF_ACK,
++      NM_MT_DISC_TERR_TRAF_NACK,
++      /* Transmission Management Messages */
++      NM_MT_CONN_MDROP_LINK           = 0x31,
++      NM_MT_CONN_MDROP_LINK_ACK,
++      NM_MT_CONN_MDROP_LINK_NACK,
++      NM_MT_DISC_MDROP_LINK,
++      NM_MT_DISC_MDROP_LINK_ACK,
++      NM_MT_DISC_MDROP_LINK_NACK,
++      /* Air Interface Management Messages */
++      NM_MT_SET_BTS_ATTR              = 0x41,
++      NM_MT_SET_BTS_ATTR_ACK,
++      NM_MT_SET_BTS_ATTR_NACK,
++      NM_MT_SET_RADIO_ATTR,
++      NM_MT_SET_RADIO_ATTR_ACK,
++      NM_MT_SET_RADIO_ATTR_NACK,
++      NM_MT_SET_CHAN_ATTR,
++      NM_MT_SET_CHAN_ATTR_ACK,
++      NM_MT_SET_CHAN_ATTR_NACK,
++      /* Test Management Messages */
++      NM_MT_PERF_TEST                 = 0x51,
++      NM_MT_PERF_TEST_ACK,
++      NM_MT_PERF_TEST_NACK,
++      NM_MT_TEST_REP,
++      NM_MT_SEND_TEST_REP,
++      NM_MT_SEND_TEST_REP_ACK,
++      NM_MT_SEND_TEST_REP_NACK,
++      NM_MT_STOP_TEST,
++      NM_MT_STOP_TEST_ACK,
++      NM_MT_STOP_TEST_NACK,
++      /* State Management and Event Report Messages */
++      NM_MT_STATECHG_EVENT_REP        = 0x61,
++      NM_MT_FAILURE_EVENT_REP,
++      NM_MT_STOP_EVENT_REP,
++      NM_MT_STOP_EVENT_REP_ACK,
++      NM_MT_STOP_EVENT_REP_NACK,
++      NM_MT_REST_EVENT_REP,
++      NM_MT_REST_EVENT_REP_ACK,
++      NM_MT_REST_EVENT_REP_NACK,
++      NM_MT_CHG_ADM_STATE,
++      NM_MT_CHG_ADM_STATE_ACK,
++      NM_MT_CHG_ADM_STATE_NACK,
++      NM_MT_CHG_ADM_STATE_REQ,
++      NM_MT_CHG_ADM_STATE_REQ_ACK,
++      NM_MT_CHG_ADM_STATE_REQ_NACK,
++      NM_MT_REP_OUTST_ALARMS          = 0x93,
++      NM_MT_REP_OUTST_ALARMS_ACK,
++      NM_MT_REP_OUTST_ALARMS_NACK,
++      /* Equipment Management Messages */
++      NM_MT_CHANGEOVER                = 0x71,
++      NM_MT_CHANGEOVER_ACK,
++      NM_MT_CHANGEOVER_NACK,
++      NM_MT_OPSTART,
++      NM_MT_OPSTART_ACK,
++      NM_MT_OPSTART_NACK,
++      NM_MT_REINIT,
++      NM_MT_REINIT_ACK,
++      NM_MT_REINIT_NACK,
++      NM_MT_SET_SITE_OUT,             /* BS11: get alarm ?!? */
++      NM_MT_SET_SITE_OUT_ACK,
++      NM_MT_SET_SITE_OUT_NACK,
++      NM_MT_CHG_HW_CONF               = 0x90,
++      NM_MT_CHG_HW_CONF_ACK,
++      NM_MT_CHG_HW_CONF_NACK,
++      /* Measurement Management Messages */
++      NM_MT_MEAS_RES_REQ              = 0x8a,
++      NM_MT_MEAS_RES_RESP,
++      NM_MT_STOP_MEAS,
++      NM_MT_START_MEAS,
++      /* Other Messages */
++      NM_MT_GET_ATTR                  = 0x81,
++      NM_MT_GET_ATTR_RESP,
++      NM_MT_GET_ATTR_NACK,
++      NM_MT_SET_ALARM_THRES,
++      NM_MT_SET_ALARM_THRES_ACK,
++      NM_MT_SET_ALARM_THRES_NACK,
++};
++
++enum abis_nm_msgtype_bs11 {
++      NM_MT_BS11_RESET_RESOURCE       = 0x74,
++
++      NM_MT_BS11_BEGIN_DB_TX          = 0xa3,
++      NM_MT_BS11_BEGIN_DB_TX_ACK,
++      NM_MT_BS11_BEGIN_DB_TX_NACK,
++      NM_MT_BS11_END_DB_TX            = 0xa6,
++      NM_MT_BS11_END_DB_TX_ACK,
++      NM_MT_BS11_END_DB_TX_NACK,
++      NM_MT_BS11_CREATE_OBJ           = 0xa9,
++      NM_MT_BS11_CREATE_OBJ_ACK,
++      NM_MT_BS11_CREATE_OBJ_NACK,
++      NM_MT_BS11_DELETE_OBJ           = 0xac,
++      NM_MT_BS11_DELETE_OBJ_ACK,
++      NM_MT_BS11_DELETE_OBJ_NACK,
++
++      NM_MT_BS11_SET_ATTR             = 0xd0,
++      NM_MT_BS11_SET_ATTR_ACK,
++      NM_MT_BS11_SET_ATTR_NACK,
++      NM_MT_BS11_LMT_SESSION          = 0xdc,
++
++      NM_MT_BS11_GET_STATE            = 0xe3,
++      NM_MT_BS11_GET_STATE_ACK,
++      NM_MT_BS11_LMT_LOGON            = 0xe5,
++      NM_MT_BS11_LMT_LOGON_ACK,
++      NM_MT_BS11_RESTART              = 0xe7,
++      NM_MT_BS11_RESTART_ACK,
++      NM_MT_BS11_DISCONNECT           = 0xe9,
++      NM_MT_BS11_DISCONNECT_ACK,
++      NM_MT_BS11_LMT_LOGOFF           = 0xec,
++      NM_MT_BS11_LMT_LOGOFF_ACK,
++      NM_MT_BS11_RECONNECT            = 0xf1,
++      NM_MT_BS11_RECONNECT_ACK,
++};
++
++enum abis_nm_msgtype_ipacc {
++      NM_MT_IPACC_RESTART             = 0x87,
++      NM_MT_IPACC_RESTART_ACK,
++      NM_MT_IPACC_RESTART_NACK,
++      NM_MT_IPACC_RSL_CONNECT         = 0xe0,
++      NM_MT_IPACC_RSL_CONNECT_ACK,
++      NM_MT_IPACC_RSL_CONNECT_NACK,
++      NM_MT_IPACC_RSL_DISCONNECT      = 0xe3,
++      NM_MT_IPACC_RSL_DISCONNECT_ACK,
++      NM_MT_IPACC_RSL_DISCONNECT_NACK,
++      NM_MT_IPACC_CONN_TRAF           = 0xe6,
++      NM_MT_IPACC_CONN_TRAF_ACK,
++      NM_MT_IPACC_CONN_TRAF_NACK,
++      NM_MT_IPACC_DEF_BOOT_SW         = 0xec,
++      NM_MT_IPACC_DEF_BOOT_SW_ACK,
++      MN_MT_IPACC_DEF_BOOT_SW_NACK,
++      NM_MT_IPACC_SET_NVATTR          = 0xef,
++      NM_MT_IPACC_SET_NVATTR_ACK,
++      NM_MT_IPACC_SET_NVATTR_NACK,
++      NM_MT_IPACC_GET_NVATTR          = 0xf2,
++      NM_MT_IPACC_GET_NVATTR_ACK,
++      NM_MT_IPACC_GET_NVATTR_NACK,
++      NM_MT_IPACC_SET_ATTR            = 0xf5,
++      NM_MT_IPACC_SET_ATTR_ACK,
++      NM_MT_IPACC_SET_ATTR_NACK,
++};
++
++enum abis_nm_bs11_cell_alloc {
++      NM_BS11_CANR_GSM        = 0x00,
++      NM_BS11_CANR_DCS1800    = 0x01,
++};
++
++/* Section 9.2: Object Class */
++enum abis_nm_obj_class {
++      NM_OC_SITE_MANAGER              = 0x00,
++      NM_OC_BTS,
++      NM_OC_RADIO_CARRIER,
++      NM_OC_CHANNEL,
++      NM_OC_BASEB_TRANSC,
++      /* RFU: 05-FE */
++
++      NM_OC_IPAC_E1_TRUNK             = 0x0e,
++      NM_OC_IPAC_E1_PORT              = 0x0f,
++      NM_OC_IPAC_E1_CHAN              = 0x10,
++      NM_OC_IPAC_CLK_MODULE           = 0x22,
++
++      NM_OC_BS11_ADJC                 = 0xa0,
++      NM_OC_BS11_HANDOVER             = 0xa1,
++      NM_OC_BS11_PWR_CTRL             = 0xa2,
++      NM_OC_BS11_BTSE                 = 0xa3,         /* LMT? */
++      NM_OC_BS11_RACK                 = 0xa4,
++      NM_OC_BS11                      = 0xa5,         /* 01: ALCO */
++      NM_OC_BS11_TEST                 = 0xa6,
++      NM_OC_BS11_ENVABTSE             = 0xa8,
++      NM_OC_BS11_BPORT                = 0xa9,
++
++      NM_OC_GPRS_NSE                  = 0xf0,
++      NM_OC_GPRS_CELL                 = 0xf1,
++      NM_OC_GPRS_NSVC                 = 0xf2,
++
++      NM_OC_NULL                      = 0xff,
++};
++
++/* Section 9.4: Attributes */
++enum abis_nm_attr {
++      NM_ATT_ABIS_CHANNEL     = 0x01,
++      NM_ATT_ADD_INFO,
++      NM_ATT_ADD_TEXT,
++      NM_ATT_ADM_STATE,
++      NM_ATT_ARFCN_LIST,
++      NM_ATT_AUTON_REPORT,
++      NM_ATT_AVAIL_STATUS,
++      NM_ATT_BCCH_ARFCN,
++      NM_ATT_BSIC,
++      NM_ATT_BTS_AIR_TIMER,
++      NM_ATT_CCCH_L_I_P,
++      NM_ATT_CCCH_L_T,
++      NM_ATT_CHAN_COMB,
++      NM_ATT_CONN_FAIL_CRIT,
++      NM_ATT_DEST,
++      /* res */
++      NM_ATT_EVENT_TYPE       = 0x11, /* BS11: file data ?!? */
++      NM_ATT_FILE_ID,
++      NM_ATT_FILE_VERSION,
++      NM_ATT_GSM_TIME,
++      NM_ATT_HSN,
++      NM_ATT_HW_CONFIG,
++      NM_ATT_HW_DESC,
++      NM_ATT_INTAVE_PARAM,
++      NM_ATT_INTERF_BOUND,
++      NM_ATT_LIST_REQ_ATTR,
++      NM_ATT_MAIO,
++      NM_ATT_MANUF_STATE,
++      NM_ATT_MANUF_THRESH,
++      NM_ATT_MANUF_ID,
++      NM_ATT_MAX_TA,
++      NM_ATT_MDROP_LINK,      /* 0x20 */
++      NM_ATT_MDROP_NEXT,
++      NM_ATT_NACK_CAUSES,
++      NM_ATT_NY1,
++      NM_ATT_OPER_STATE,
++      NM_ATT_OVERL_PERIOD,
++      NM_ATT_PHYS_CONF,
++      NM_ATT_POWER_CLASS,
++      NM_ATT_POWER_THRESH,
++      NM_ATT_PROB_CAUSE,
++      NM_ATT_RACH_B_THRESH,
++      NM_ATT_LDAVG_SLOTS,
++      NM_ATT_RAD_SUBC,
++      NM_ATT_RF_MAXPOWR_R,
++      NM_ATT_SITE_INPUTS,
++      NM_ATT_SITE_OUTPUTS,
++      NM_ATT_SOURCE,          /* 0x30 */
++      NM_ATT_SPEC_PROB,
++      NM_ATT_START_TIME,
++      NM_ATT_T200,
++      NM_ATT_TEI,
++      NM_ATT_TEST_DUR,
++      NM_ATT_TEST_NO,
++      NM_ATT_TEST_REPORT,
++      NM_ATT_VSWR_THRESH,
++      NM_ATT_WINDOW_SIZE,
++      /* Res  */
++      NM_ATT_BS11_RSSI_OFFS   = 0x3d,
++      NM_ATT_BS11_TXPWR       = 0x3e,
++      NM_ATT_BS11_DIVERSITY   = 0x3f,
++      /* Res  */
++      NM_ATT_TSC              = 0x40,
++      NM_ATT_SW_CONFIG,
++      NM_ATT_SW_DESCR,
++      NM_ATT_SEVERITY,
++      NM_ATT_GET_ARI,
++      NM_ATT_HW_CONF_CHG,
++      NM_ATT_OUTST_ALARM,
++      NM_ATT_FILE_DATA,
++      NM_ATT_MEAS_RES,
++      NM_ATT_MEAS_TYPE,
++
++      NM_ATT_BS11_ESN_FW_CODE_NO      = 0x4c,
++      NM_ATT_BS11_ESN_HW_CODE_NO      = 0x4f,
++
++      NM_ATT_BS11_ESN_PCB_SERIAL      = 0x55,
++      NM_ATT_BS11_EXCESSIVE_DISTANCE  = 0x58,
++
++      NM_ATT_BS11_ALL_TEST_CATG       = 0x60,
++      NM_ATT_BS11_BTSLS_HOPPING,
++      NM_ATT_BS11_CELL_ALLOC_NR,
++      NM_ATT_BS11_CELL_GLOBAL_ID,
++      NM_ATT_BS11_ENA_INTERF_CLASS    = 0x66,
++      NM_ATT_BS11_ENA_INT_INTEC_HANDO = 0x67,
++      NM_ATT_BS11_ENA_INT_INTRC_HANDO = 0x68,
++      NM_ATT_BS11_ENA_MS_PWR_CTRL     = 0x69,
++      NM_ATT_BS11_ENA_PWR_BDGT_HO     = 0x6a,
++      NM_ATT_BS11_ENA_PWR_CTRL_RLFW   = 0x6b,
++      NM_ATT_BS11_ENA_RXLEV_HO        = 0x6c,
++      NM_ATT_BS11_ENA_RXQUAL_HO       = 0x6d,
++      NM_ATT_BS11_FACCH_QUAL          = 0x6e,
++
++      NM_ATT_IPACC_DST_IP             = 0x80,
++      NM_ATT_IPACC_DST_IP_PORT        = 0x81,
++      NM_ATT_IPACC_SSRC               = 0x82,
++      NM_ATT_IPACC_RTP_PAYLD_TYPE     = 0x83,
++      NM_ATT_IPACC_BASEB_ID           = 0x84,
++      NM_ATT_IPACC_STREAM_ID          = 0x85,
++      NM_ATT_IPACC_NV_FLAGS           = 0x86,
++      NM_ATT_IPACC_FREQ_CTRL          = 0x87,
++      NM_ATT_IPACC_PRIM_OML_CFG       = 0x88,
++      NM_ATT_IPACC_SEC_OML_CFG        = 0x89,
++      NM_ATT_IPACC_IP_IF_CFG          = 0x8a,         /* IP interface */
++      NM_ATT_IPACC_IP_GW_CFG          = 0x8b,         /* IP gateway */
++      NM_ATT_IPACC_IN_SERV_TIME       = 0x8c,
++      NM_ATT_IPACC_TRX_BTS_ASS        = 0x8d,
++      NM_ATT_IPACC_LOCATION           = 0x8e,         /* string describing location */
++      NM_ATT_IPACC_PAGING_CFG         = 0x8f,
++      NM_ATT_IPACC_FILE_DATA          = 0x90,
++      NM_ATT_IPACC_UNIT_ID            = 0x91,         /* Site/BTS/TRX */
++      NM_ATT_IPACC_PARENT_UNIT_ID     = 0x92,
++      NM_ATT_IPACC_UNIT_NAME          = 0x93,         /* default: nbts-<mac-as-string> */
++      NM_ATT_IPACC_SNMP_CFG           = 0x94,
++      NM_ATT_IPACC_PRIM_OML_CFG_LIST  = 0x95,
++      NM_ATT_IPACC_PRIM_OML_FB_TOUT   = 0x96,
++      NM_ATT_IPACC_CUR_SW_CFG         = 0x97,
++      NM_ATT_IPACC_TIMING_BUS         = 0x98,
++      NM_ATT_IPACC_CGI                = 0x99,
++      NM_ATT_IPACC_RAC                = 0x9a,
++      NM_ATT_IPACC_OBJ_VERSION        = 0x9b,
++      NM_ATT_IPACC_GPRS_PAGING_CFG    = 0x9c,
++      NM_ATT_IPACC_NSEI               = 0x9d,
++      NM_ATT_IPACC_BVCI               = 0x9e,
++      NM_ATT_IPACC_NSVCI              = 0x9f,
++      NM_ATT_IPACC_NS_CFG             = 0xa0,
++      NM_ATT_IPACC_BSSGP_CFG          = 0xa1,
++      NM_ATT_IPACC_NS_LINK_CFG        = 0xa2,
++      NM_ATT_IPACC_RLC_CFG            = 0xa3, 
++      NM_ATT_IPACC_ALM_THRESH_LIST    = 0xa4,
++      NM_ATT_IPACC_MONIT_VAL_LIST     = 0xa5,
++      NM_ATT_IPACC_TIB_CONTROL        = 0xa6,
++      NM_ATT_IPACC_SUPP_FEATURES      = 0xa7,
++      NM_ATT_IPACC_CODING_SCHEMES     = 0xa8,
++      NM_ATT_IPACC_RLC_CFG_2          = 0xa9,
++      NM_ATT_IPACC_HEARTB_TOUT        = 0xaa,
++      NM_ATT_IPACC_UPTIME             = 0xab,
++      NM_ATT_IPACC_RLC_CFG_3          = 0xac,
++      NM_ATT_IPACC_SSL_CFG            = 0xad,
++      NM_ATT_IPACC_SEC_POSSIBLE       = 0xae,
++      NM_ATT_IPACC_IML_SSL_STATE      = 0xaf,
++      NM_ATT_IPACC_REVOC_DATE         = 0xb0,
++
++
++      NM_ATT_BS11_RF_RES_IND_PER      = 0x8f,
++      
++      NM_ATT_BS11_RX_LEV_MIN_CELL     = 0x90,
++      NM_ATT_BS11_ABIS_EXT_TIME       = 0x91,
++      NM_ATT_BS11_TIMER_HO_REQUEST    = 0x92,
++      NM_ATT_BS11_TIMER_NCELL         = 0x93,
++      NM_ATT_BS11_TSYNC               = 0x94,
++      NM_ATT_BS11_TTRAU               = 0x95,
++      NM_ATT_BS11_EMRG_CFG_MEMBER     = 0x9b,
++      NM_ATT_BS11_TRX_AREA            = 0x9f,
++
++      NM_ATT_BS11_BCCH_RECONF         = 0xd7,
++      NM_ATT_BS11_BIT_ERR_THESH       = 0xa0,
++      NM_ATT_BS11_BOOT_SW_VERS        = 0xa1,
++      NM_ATT_BS11_CCLK_ACCURACY       = 0xa3,
++      NM_ATT_BS11_CCLK_TYPE           = 0xa4,
++      NM_ATT_BS11_INP_IMPEDANCE       = 0xaa,
++      NM_ATT_BS11_L1_PROT_TYPE        = 0xab,
++      NM_ATT_BS11_LINE_CFG            = 0xac,
++      NM_ATT_BS11_LI_PORT_1           = 0xad,
++      NM_ATT_BS11_LI_PORT_2           = 0xae,
++
++      NM_ATT_BS11_L1_REM_ALM_TYPE     = 0xb0,
++      NM_ATT_BS11_SW_LOAD_INTENDED    = 0xbb,
++      NM_ATT_BS11_SW_LOAD_SAFETY      = 0xbc,
++      NM_ATT_BS11_SW_LOAD_STORED      = 0xbd,
++
++      NM_ATT_BS11_VENDOR_NAME         = 0xc1,
++      NM_ATT_BS11_HOPPING_MODE        = 0xc5,
++      NM_ATT_BS11_LMT_LOGON_SESSION   = 0xc6,
++      NM_ATT_BS11_LMT_LOGIN_TIME      = 0xc7,
++      NM_ATT_BS11_LMT_USER_ACC_LEV    = 0xc8,
++      NM_ATT_BS11_LMT_USER_NAME       = 0xc9,
++
++      NM_ATT_BS11_L1_CONTROL_TS       = 0xd8,
++      NM_ATT_BS11_RADIO_MEAS_GRAN     = 0xdc, /* in SACCH multiframes */
++      NM_ATT_BS11_RADIO_MEAS_REP      = 0xdd,
++
++      NM_ATT_BS11_SH_LAPD_INT_TIMER   = 0xe8,
++
++      NM_ATT_BS11_BTS_STATE           = 0xf0,
++      NM_ATT_BS11_E1_STATE            = 0xf1,
++      NM_ATT_BS11_PLL                 = 0xf2,
++      NM_ATT_BS11_RX_OFFSET           = 0xf3,
++      NM_ATT_BS11_ANT_TYPE            = 0xf4,
++      NM_ATT_BS11_PLL_MODE            = 0xfc,
++      NM_ATT_BS11_PASSWORD            = 0xfd,
++};
++#define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE
++
++/* Section 9.4.4: Administrative State */
++enum abis_nm_adm_state {
++      NM_STATE_LOCKED         = 0x01,
++      NM_STATE_UNLOCKED       = 0x02,
++      NM_STATE_SHUTDOWN       = 0x03,
++      NM_STATE_NULL           = 0xff,
++};
++
++/* Section 9.4.7: Administrative State */
++enum abis_nm_avail_state {
++      NM_AVSTATE_IN_TEST      = 1,
++      NM_AVSTATE_POWER_OFF    = 2,
++      NM_AVSTATE_OFF_LINE     = 3,
++      NM_AVSTATE_DEPENDENCY   = 5,
++      NM_AVSTATE_DEGRADED     = 6,
++      NM_AVSTATE_NOT_INSTALLED= 7,
++      NM_AVSTATE_OK           = 0xff,
++};
++
++enum abis_nm_op_state {
++      NM_OPSTATE_DISABLED     = 1,
++      NM_OPSTATE_ENABLED      = 2,
++      NM_OPSTATE_NULL         = 0xff,
++};
++
++/* Section 9.4.13: Channel Combination */
++enum abis_nm_chan_comb {
++      NM_CHANC_TCHFull        = 0x00, /* TCH/F + TCH/H + SACCH/TF */
++      NM_CHANC_TCHHalf        = 0x01, /* TCH/H(0,1) + FACCH/H(0,1) +
++                                         SACCH/TH(0,1) */
++      NM_CHANC_TCHHalf2       = 0x02, /* TCH/H(0) + FACCH/H(0) + SACCH/TH(0) +
++                                         TCH/H(1) */
++      NM_CHANC_SDCCH          = 0x03, /* SDCCH/8 + SACCH/8 */
++      NM_CHANC_mainBCCH       = 0x04, /* FCCH + SCH + BCCH + CCCH */
++      NM_CHANC_BCCHComb       = 0x05, /* FCCH + SCH + BCCH + CCCH + SDCCH/4 +
++                                         SACCH/C4 */
++      NM_CHANC_BCCH           = 0x06, /* BCCH + CCCH */
++      NM_CHANC_BCCH_CBCH      = 0x07, /* CHANC_BCCHComb + CBCH */
++      NM_CHANC_SDCCH_CBCH     = 0x08, /* CHANC_SDCCH8 + CBCH */
++      /* ip.access */
++      NM_CHANC_IPAC_bPDCH     = 0x0b, /* PBCCH + PCCCH + PDTCH/F + PACCH/F +
++                                         PTCCH/F */
++      NM_CHANC_IPAC_cPDCH     = 0x0c, /* PBCCH + PDTCH/F + PACCH/F + PTCCH/F */
++      NM_CHANC_IPAC_PDCH      = 0x0d, /* PDTCH/F + PACCH/F + PTCCH/F */
++      NM_CHANC_IPAC_TCHFull_PDCH = 0x80,
++      NM_CHANC_IPAC_TCHFull_TCHHalf = 0x81,
++};
++
++/* Section 9.4.16: Event Type */
++enum abis_nm_event_type {
++      NM_EVT_COMM_FAIL        = 0x00,
++      NM_EVT_QOS_FAIL         = 0x01,
++      NM_EVT_PROC_FAIL        = 0x02,
++      NM_EVT_EQUIP_FAIL       = 0x03,
++      NM_EVT_ENV_FAIL         = 0x04,
++};
++
++/* Section: 9.4.63: Perceived Severity */
++enum abis_nm_severity {
++      NM_SEVER_CEASED         = 0x00,
++      NM_SEVER_CRITICAL       = 0x01,
++      NM_SEVER_MAJOR          = 0x02,
++      NM_SEVER_MINOR          = 0x03,
++      NM_SEVER_WARNING        = 0x04,
++      NM_SEVER_INDETERMINATE  = 0x05,
++};
++
++/* Section 9.4.43: Probable Cause Type */
++enum abis_nm_pcause_type {
++      NM_PCAUSE_T_X721        = 0x01,
++      NM_PCAUSE_T_GSM         = 0x02,
++      NM_PCAUSE_T_MANUF       = 0x03,
++};
++
++/* Section 9.4.36: NACK Causes */
++enum abis_nm_nack_cause {
++      /* General Nack Causes */
++      NM_NACK_INCORR_STRUCT           = 0x01,
++      NM_NACK_MSGTYPE_INVAL           = 0x02,
++      NM_NACK_OBJCLASS_INVAL          = 0x05,
++      NM_NACK_OBJCLASS_NOTSUPP        = 0x06,
++      NM_NACK_BTSNR_UNKN              = 0x07,
++      NM_NACK_TRXNR_UNKN              = 0x08,
++      NM_NACK_OBJINST_UNKN            = 0x09,
++      NM_NACK_ATTRID_INVAL            = 0x0c,
++      NM_NACK_ATTRID_NOTSUPP          = 0x0d,
++      NM_NACK_PARAM_RANGE             = 0x0e,
++      NM_NACK_ATTRLIST_INCONSISTENT   = 0x0f,
++      NM_NACK_SPEC_IMPL_NOTSUPP       = 0x10,
++      NM_NACK_CANT_PERFORM            = 0x11,
++      /* Specific Nack Causes */
++      NM_NACK_RES_NOTIMPL             = 0x19,
++      NM_NACK_RES_NOTAVAIL            = 0x1a,
++      NM_NACK_FREQ_NOTAVAIL           = 0x1b,
++      NM_NACK_TEST_NOTSUPP            = 0x1c,
++      NM_NACK_CAPACITY_RESTR          = 0x1d,
++      NM_NACK_PHYSCFG_NOTPERFORM      = 0x1e,
++      NM_NACK_TEST_NOTINIT            = 0x1f,
++      NM_NACK_PHYSCFG_NOTRESTORE      = 0x20,
++      NM_NACK_TEST_NOSUCH             = 0x21,
++      NM_NACK_TEST_NOSTOP             = 0x22,
++      NM_NACK_MSGINCONSIST_PHYSCFG    = 0x23,
++      NM_NACK_FILE_INCOMPLETE         = 0x25,
++      NM_NACK_FILE_NOTAVAIL           = 0x26,
++      NM_NACK_FILE_NOTACTIVATE        = 0x27,
++      NM_NACK_REQ_NOT_GRANT           = 0x28,
++      NM_NACK_WAIT                    = 0x29,
++      NM_NACK_NOTH_REPORT_EXIST       = 0x2a,
++      NM_NACK_MEAS_NOTSUPP            = 0x2b,
++      NM_NACK_MEAS_NOTSTART           = 0x2c,
++};
++
++/* Section 9.4.1 */
++struct abis_nm_channel {
++      uint8_t attrib;
++      uint8_t bts_port;
++      uint8_t timeslot;
++      uint8_t subslot;
++} __attribute__ ((packed));
++
++/* Siemens BS-11 specific objects in the SienemsHW (0xA5) object class */
++enum abis_bs11_objtype {
++      BS11_OBJ_ALCO           = 0x01,
++      BS11_OBJ_BBSIG          = 0x02, /* obj_class: 0,1 */
++      BS11_OBJ_TRX1           = 0x03, /* only DEACTIVATE TRX1 */
++      BS11_OBJ_CCLK           = 0x04,
++      BS11_OBJ_GPSU           = 0x06,
++      BS11_OBJ_LI             = 0x07,
++      BS11_OBJ_PA             = 0x09, /* obj_class: 0, 1*/
++};
++
++enum abis_bs11_trx_power {
++      BS11_TRX_POWER_GSM_2W   = 0x06,
++      BS11_TRX_POWER_GSM_250mW= 0x07,
++      BS11_TRX_POWER_GSM_80mW = 0x08,
++      BS11_TRX_POWER_GSM_30mW = 0x09,
++      BS11_TRX_POWER_DCS_3W   = 0x0a,
++      BS11_TRX_POWER_DCS_1W6  = 0x0b,
++      BS11_TRX_POWER_DCS_500mW= 0x0c,
++      BS11_TRX_POWER_DCS_160mW= 0x0d,
++};
++
++enum abis_bs11_li_pll_mode {
++      BS11_LI_PLL_LOCKED      = 2,
++      BS11_LI_PLL_STANDALONE  = 3,
++};
++
++enum abis_bs11_line_cfg {
++      BS11_LINE_CFG_STAR      = 0x00,
++      BS11_LINE_CFG_MULTIDROP = 0x01,
++      BS11_LINE_CFG_LOOP      = 0x02,
++};
++
++enum abis_bs11_phase {
++      BS11_STATE_SOFTWARE_RQD         = 0x01,
++      BS11_STATE_LOAD_SMU_INTENDED    = 0x11,
++      BS11_STATE_LOAD_SMU_SAFETY      = 0x21,
++      BS11_STATE_LOAD_FAILED          = 0x31,
++      BS11_STATE_LOAD_DIAGNOSTIC      = 0x41,
++      BS11_STATE_WARM_UP              = 0x51,
++      BS11_STATE_WARM_UP_2            = 0x52,
++      BS11_STATE_WAIT_MIN_CFG         = 0x62,
++      BS11_STATE_MAINTENANCE          = 0x72,
++      BS11_STATE_LOAD_MBCCU           = 0x92,
++      BS11_STATE_WAIT_MIN_CFG_2       = 0xA2,
++      BS11_STATE_NORMAL               = 0x03,
++      BS11_STATE_ABIS_LOAD            = 0x13,
++};
++
++enum abis_nm_ipacc_test_no {
++      NM_IPACC_TESTNO_RLOOP_ANT       = 0x01,
++      NM_IPACC_TESTNO_RLOOP_XCVR      = 0x02,
++      NM_IPACC_TESTNO_FUNC_OBJ        = 0x03,
++      NM_IPACC_TESTNO_CHAN_USAGE      = 0x40,
++      NM_IPACC_TESTNO_BCCH_CHAN_USAGE = 0x41,
++      NM_IPACC_TESTNO_FREQ_SYNC       = 0x42,
++      NM_IPACC_TESTNO_BCCH_INFO       = 0x43,
++      NM_IPACC_TESTNO_TX_BEACON       = 0x44,
++      NM_IPACC_TESTNO_SYSINFO_MONITOR = 0x45,
++      NM_IPACC_TESTNO_BCCCH_MONITOR   = 0x46,
++};
++
++/* first byte after length inside NM_ATT_TEST_REPORT */
++enum abis_nm_ipacc_test_res {
++      NM_IPACC_TESTRES_SUCCESS        = 0,
++      NM_IPACC_TESTRES_TIMEOUT        = 1,
++      NM_IPACC_TESTRES_NO_CHANS       = 2,
++      NM_IPACC_TESTRES_PARTIAL        = 3,
++      NM_IPACC_TESTRES_STOPPED        = 4,
++};
++
++/* internal IE inside NM_ATT_TEST_REPORT */
++enum abis_nm_ipacc_testres_ie {
++      NM_IPACC_TR_IE_FREQ_ERR_LIST    = 3,
++      NM_IPACC_TR_IE_CHAN_USAGE       = 4,
++      NM_IPACC_TR_IE_BCCH_INFO        = 6,
++      NM_IPACC_TR_IE_RESULT_DETAILS   = 8,
++      NM_IPACC_TR_IE_FREQ_ERR         = 18,
++};
++
++enum ipac_eie {
++      NM_IPAC_EIE_ARFCN_WHITE         = 0x01,
++      NM_IPAC_EIE_ARFCH_BLACK         = 0x02,
++      NM_IPAC_EIE_FREQ_ERR_LIST       = 0x03,
++      NM_IPAC_EIE_CHAN_USE_LIST       = 0x04,
++      NM_IPAC_EIE_BCCH_INFO_TYPE      = 0x05,
++      NM_IPAC_EIE_BCCH_INFO           = 0x06,
++      /* FIXME */
++};
++
++enum ipac_bcch_info_type {
++      IPAC_BINF_RXLEV                 = (1 << 8),
++      IPAC_BINF_RXQUAL                = (1 << 9),
++      IPAC_BINF_FREQ_ERR_QUAL         = (1 << 10),
++      IPAC_BINF_FRAME_OFFSET          = (1 << 11),
++      IPAC_BINF_FRAME_NR_OFFSET       = (1 << 12),
++      IPAC_BINF_BSIC                  = (1 << 13),
++      IPAC_BINF_CGI                   = (1 << 14),
++      IPAC_BINF_NEIGH_BA_SI2          = (1 << 15),
++      IPAC_BINF_NEIGH_BA_SI2bis       = (1 << 0),
++      IPAC_BINF_NEIGH_BA_SI2ter       = (1 << 1),
++      IPAC_BINF_CELL_ALLOC            = (1 << 2),
++};
++
++#endif /* PROTO_GSM_12_21_H */
index 0000000,0000000..2d8b3ec
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++#ifndef _BSC_SELECT_H
++#define _BSC_SELECT_H
++
++#include "linuxlist.h"
++
++#define BSC_FD_READ   0x0001
++#define BSC_FD_WRITE  0x0002
++#define BSC_FD_EXCEPT 0x0004
++
++struct bsc_fd {
++      struct llist_head list;
++      int fd;
++      unsigned int when;
++      int (*cb)(struct bsc_fd *fd, unsigned int what);
++      void *data;
++      unsigned int priv_nr;
++};
++
++int bsc_register_fd(struct bsc_fd *fd);
++void bsc_unregister_fd(struct bsc_fd *fd);
++int bsc_select_main(int polling);
++#endif /* _BSC_SELECT_H */
index 0000000,0000000..02d83d2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++#ifndef OSMOCORE_SIGNAL_H
++#define OSMOCORE_SIGNAL_H
++
++typedef int signal_cbfn(unsigned int subsys, unsigned int signal,
++                      void *handler_data, void *signal_data);
++
++
++/* Management */
++int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data);
++void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data);
++
++/* Dispatch */
++void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data);
++
++#endif /* OSMOCORE_SIGNAL_H */
index 0000000,0000000..1d56054
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++#ifndef _STATISTICS_H
++#define _STATISTICS_H
++
++struct counter {
++      struct llist_head list;
++      const char *name;
++      const char *description;
++      unsigned long value;
++};
++
++static inline void counter_inc(struct counter *ctr)
++{
++      ctr->value++;
++}
++
++static inline unsigned long counter_get(struct counter *ctr)
++{
++      return ctr->value;
++}
++
++static inline void counter_reset(struct counter *ctr)
++{
++      ctr->value = 0;
++}
++
++struct counter *counter_alloc(const char *name);
++void counter_free(struct counter *ctr);
++
++int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data);
++
++#endif /* _STATISTICS_H */
index 0000000,0000000..f7f7643
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,192 @@@
++#ifndef _TALLOC_H_
++#define _TALLOC_H_
++/* 
++   Unix SMB/CIFS implementation.
++   Samba temporary memory allocation functions
++
++   Copyright (C) Andrew Tridgell 2004-2005
++   Copyright (C) Stefan Metzmacher 2006
++   
++     ** NOTE! The following LGPL license applies to the talloc
++     ** library. This does NOT imply that all of Samba is released
++     ** under the LGPL
++   
++   This library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 3 of the License, or (at your option) any later version.
++
++   This library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with this library; if not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <stdarg.h>
++
++#define HAVE_VA_COPY
++
++/* this is only needed for compatibility with the old talloc */
++typedef void TALLOC_CTX;
++
++/*
++  this uses a little trick to allow __LINE__ to be stringified
++*/
++#ifndef __location__
++#define __TALLOC_STRING_LINE1__(s)    #s
++#define __TALLOC_STRING_LINE2__(s)   __TALLOC_STRING_LINE1__(s)
++#define __TALLOC_STRING_LINE3__  __TALLOC_STRING_LINE2__(__LINE__)
++#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
++#endif
++
++#ifndef TALLOC_DEPRECATED
++#define TALLOC_DEPRECATED 0
++#endif
++
++#ifndef PRINTF_ATTRIBUTE
++#if (__GNUC__ >= 3)
++/** Use gcc attribute to check printf fns.  a1 is the 1-based index of
++ * the parameter containing the format, and a2 the index of the first
++ * argument. Note that some gcc 2.x versions don't handle this
++ * properly **/
++#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
++#else
++#define PRINTF_ATTRIBUTE(a1, a2)
++#endif
++#endif
++
++/* try to make talloc_set_destructor() and talloc_steal() type safe,
++   if we have a recent gcc */
++#if (__GNUC__ >= 3)
++#define _TALLOC_TYPEOF(ptr) __typeof__(ptr)
++#define talloc_set_destructor(ptr, function)                                \
++      do {                                                                  \
++              int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function);       \
++              _talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \
++      } while(0)
++/* this extremely strange macro is to avoid some braindamaged warning
++   stupidity in gcc 4.1.x */
++#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr)); __talloc_steal_ret; })
++#else
++#define talloc_set_destructor(ptr, function) \
++      _talloc_set_destructor((ptr), (int (*)(void *))(function))
++#define _TALLOC_TYPEOF(ptr) void *
++#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal((ctx),(ptr))
++#endif
++
++#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference((ctx),(ptr))
++#define talloc_move(ctx, ptr) (_TALLOC_TYPEOF(*(ptr)))_talloc_move((ctx),(void *)(ptr))
++
++/* useful macros for creating type checked pointers */
++#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type)
++#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
++#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr)))
++
++#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__)
++
++#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
++#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
++
++#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type)
++#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
++#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
++#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
++#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx))
++
++#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
++#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
++
++#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__)
++
++#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
++#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
++#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
++
++#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
++
++#if TALLOC_DEPRECATED
++#define talloc_zero_p(ctx, type) talloc_zero(ctx, type)
++#define talloc_p(ctx, type) talloc(ctx, type)
++#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count)
++#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count)
++#define talloc_destroy(ctx) talloc_free(ctx)
++#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
++#endif
++
++#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
++
++/* The following definitions come from talloc.c  */
++void *_talloc(const void *context, size_t size);
++void *talloc_pool(const void *context, size_t size);
++void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *));
++int talloc_increase_ref_count(const void *ptr);
++size_t talloc_reference_count(const void *ptr);
++void *_talloc_reference(const void *context, const void *ptr);
++int talloc_unlink(const void *context, void *ptr);
++const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
++void talloc_set_name_const(const void *ptr, const char *name);
++void *talloc_named(const void *context, size_t size, 
++                 const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
++void *talloc_named_const(const void *context, size_t size, const char *name);
++const char *talloc_get_name(const void *ptr);
++void *talloc_check_name(const void *ptr, const char *name);
++void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
++void *talloc_parent(const void *ptr);
++const char *talloc_parent_name(const void *ptr);
++void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
++int talloc_free(void *ptr);
++void talloc_free_children(void *ptr);
++void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name);
++void *_talloc_steal(const void *new_ctx, const void *ptr);
++void *_talloc_move(const void *new_ctx, const void *pptr);
++size_t talloc_total_size(const void *ptr);
++size_t talloc_total_blocks(const void *ptr);
++void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
++                          void (*callback)(const void *ptr,
++                                           int depth, int max_depth,
++                                           int is_ref,
++                                           void *private_data),
++                          void *private_data);
++void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f);
++void talloc_report_full(const void *ptr, FILE *f);
++void talloc_report(const void *ptr, FILE *f);
++void talloc_enable_null_tracking(void);
++void talloc_disable_null_tracking(void);
++void talloc_enable_leak_report(void);
++void talloc_enable_leak_report_full(void);
++void *_talloc_zero(const void *ctx, size_t size, const char *name);
++void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name);
++void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name);
++void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name);
++void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name);
++void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
++void *talloc_autofree_context(void);
++size_t talloc_get_size(const void *ctx);
++void *talloc_find_parent_byname(const void *ctx, const char *name);
++void talloc_show_parents(const void *context, FILE *file);
++int talloc_is_parent(const void *context, const void *ptr);
++
++char *talloc_strdup(const void *t, const char *p);
++char *talloc_strdup_append(char *s, const char *a);
++char *talloc_strdup_append_buffer(char *s, const char *a);
++
++char *talloc_strndup(const void *t, const char *p, size_t n);
++char *talloc_strndup_append(char *s, const char *a, size_t n);
++char *talloc_strndup_append_buffer(char *s, const char *a, size_t n);
++
++char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
++char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
++char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
++
++char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
++char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
++char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
++
++void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
++
++#endif
index 0000000,0000000..fee888b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,72 @@@
++/*
++ * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#ifndef TIMER_H
++#define TIMER_H
++
++#include <sys/time.h>
++
++#include "linuxlist.h"
++
++/**
++ * Timer management:
++ *      - Create a struct timer_list
++ *      - Fill out timeout and use add_timer or
++ *        use schedule_timer to schedule a timer in
++ *        x seconds and microseconds from now...
++ *      - Use del_timer to remove the timer
++ *
++ *  Internally:
++ *      - We hook into select.c to give a timeval of the
++ *        nearest timer. On already passed timers we give
++ *        it a 0 to immediately fire after the select
++ *      - update_timers will call the callbacks and remove
++ *        the timers.
++ *
++ */
++struct timer_list {
++      struct llist_head entry;
++      struct timeval timeout;
++      unsigned int active  : 1;
++      unsigned int handled : 1;
++      unsigned int in_list : 1;
++
++      void (*cb)(void*);
++      void *data;
++};
++
++/**
++ * timer management
++ */
++void bsc_add_timer(struct timer_list *timer);
++void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds);
++void bsc_del_timer(struct timer_list *timer);
++int bsc_timer_pending(struct timer_list *timer);
++
++
++/**
++ * internal timer list management
++ */
++struct timeval *bsc_nearest_timer();
++void bsc_prepare_timers();
++int bsc_update_timers();
++int bsc_timer_check(void);
++
++#endif
index 0000000,0000000..14c9910
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,237 @@@
++#ifndef _TLV_H
++#define _TLV_H
++
++#include <stdint.h>
++#include <string.h>
++
++#include <osmocore/msgb.h>
++
++/* Terminology / wording
++              tag     length          value   (in bits)
++
++          V   -       -               8
++         LV   -       8               N * 8
++        TLV   8       8               N * 8
++      TL16V   8       16              N * 8
++      TLV16   8       8               N * 16
++       TvLV   8       8/16            N * 8
++
++*/
++
++#define LV_GROSS_LEN(x)               (x+1)
++#define TLV_GROSS_LEN(x)      (x+2)
++#define TLV16_GROSS_LEN(x)    ((2*x)+2)
++#define TL16V_GROSS_LEN(x)    (x+3)
++#define L16TV_GROSS_LEN(x)    (x+3)
++
++#define TVLV_MAX_ONEBYTE      0x7f
++
++static inline uint16_t TVLV_GROSS_LEN(uint16_t len)
++{
++      if (len <= TVLV_MAX_ONEBYTE)
++              return TLV_GROSS_LEN(len);
++      else
++              return TL16V_GROSS_LEN(len);
++}
++
++/* TLV generation */
++
++static inline uint8_t *lv_put(uint8_t *buf, uint8_t len,
++                              const uint8_t *val)
++{
++      *buf++ = len;
++      memcpy(buf, val, len);
++      return buf + len;
++}
++
++static inline uint8_t *tlv_put(uint8_t *buf, uint8_t tag, uint8_t len,
++                              const uint8_t *val)
++{
++      *buf++ = tag;
++      *buf++ = len;
++      memcpy(buf, val, len);
++      return buf + len;
++}
++
++static inline uint8_t *tlv16_put(uint8_t *buf, uint8_t tag, uint8_t len,
++                              const uint16_t *val)
++{
++      *buf++ = tag;
++      *buf++ = len;
++      memcpy(buf, val, len*2);
++      return buf + len*2;
++}
++
++static inline uint8_t *tl16v_put(uint8_t *buf, uint8_t tag, uint16_t len,
++                              const uint8_t *val)
++{
++      *buf++ = tag;
++      *buf++ = len >> 8;
++      *buf++ = len & 0xff;
++      memcpy(buf, val, len);
++      return buf + len*2;
++}
++
++static inline uint8_t *tvlv_put(uint8_t *buf, uint8_t tag, uint16_t len,
++                               const uint8_t *val)
++{
++      uint8_t *ret;
++
++      if (len <= TVLV_MAX_ONEBYTE) {
++              ret = tlv_put(buf, tag, len, val);
++              buf[1] |= 0x80;
++      } else
++              ret = tl16v_put(buf, tag, len, val);
++
++      return ret;
++}
++
++static inline uint8_t *msgb_tlv16_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint16_t *val)
++{
++      uint8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
++      return tlv16_put(buf, tag, len, val);
++}
++
++static inline uint8_t *msgb_tl16v_put(struct msgb *msg, uint8_t tag, uint16_t len,
++                                      const uint8_t *val)
++{
++      uint8_t *buf = msgb_put(msg, TL16V_GROSS_LEN(len));
++      return tl16v_put(buf, tag, len, val);
++}
++
++static inline uint8_t *msgb_tvlv_put(struct msgb *msg, uint8_t tag, uint16_t len,
++                                    const uint8_t *val)
++{
++      uint8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len));
++      return tvlv_put(buf, tag, len, val);
++}
++
++static inline uint8_t *msgb_l16tv_put(struct msgb *msg, uint16_t len, uint8_t tag,
++                                       const uint8_t *val)
++{
++      uint8_t *buf = msgb_put(msg, L16TV_GROSS_LEN(len));
++
++      *buf++ = len >> 8;
++      *buf++ = len & 0xff;
++      *buf++ = tag;
++      memcpy(buf, val, len);
++      return buf + len;
++}
++
++static inline uint8_t *v_put(uint8_t *buf, uint8_t val)
++{
++      *buf++ = val;
++      return buf;
++}
++
++static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag, 
++                              uint8_t val)
++{
++      *buf++ = tag;
++      *buf++ = val;
++      return buf;
++}
++
++/* 'val' is still in host byte order! */
++static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag, 
++                               uint16_t val)
++{
++      *buf++ = tag;
++      *buf++ = val >> 8;
++      *buf++ = val & 0xff;
++      return buf;
++}
++
++static inline uint8_t *msgb_lv_put(struct msgb *msg, uint8_t len, const uint8_t *val)
++{
++      uint8_t *buf = msgb_put(msg, LV_GROSS_LEN(len));
++      return lv_put(buf, len, val);
++}
++
++static inline uint8_t *msgb_tlv_put(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
++{
++      uint8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
++      return tlv_put(buf, tag, len, val);
++}
++
++static inline uint8_t *msgb_tv_put(struct msgb *msg, uint8_t tag, uint8_t val)
++{
++      uint8_t *buf = msgb_put(msg, 2);
++      return tv_put(buf, tag, val);
++}
++
++static inline uint8_t *msgb_v_put(struct msgb *msg, uint8_t val)
++{
++      uint8_t *buf = msgb_put(msg, 1);
++      return v_put(buf, val);
++}
++
++static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val)
++{
++      uint8_t *buf = msgb_put(msg, 3);
++      return tv16_put(buf, tag, val);
++}
++
++static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val)
++{
++      uint8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
++      return tlv_put(buf, tag, len, val);
++}
++
++static inline uint8_t *msgb_tv_push(struct msgb *msg, uint8_t tag, uint8_t val)
++{
++      uint8_t *buf = msgb_push(msg, 2);
++      return tv_put(buf, tag, val);
++}
++
++static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t val)
++{
++      uint8_t *buf = msgb_push(msg, 3);
++      return tv16_put(buf, tag, val);
++}
++
++/* TLV parsing */
++
++struct tlv_p_entry {
++      uint16_t len;
++      const uint8_t *val;
++};
++
++enum tlv_type {
++      TLV_TYPE_NONE,
++      TLV_TYPE_FIXED,
++      TLV_TYPE_T,
++      TLV_TYPE_TV,
++      TLV_TYPE_TLV,
++      TLV_TYPE_TL16V,
++      TLV_TYPE_TvLV,
++};
++
++struct tlv_def {
++      enum tlv_type type;
++      uint8_t fixed_len;
++};
++
++struct tlv_definition {
++      struct tlv_def def[0xff];
++};
++
++struct tlv_parsed {
++      struct tlv_p_entry lv[0xff];
++};
++
++extern struct tlv_definition tvlv_att_def;
++
++int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
++                  const struct tlv_definition *def,
++                  const uint8_t *buf, int buf_len);
++int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
++            const uint8_t *buf, int buf_len, uint8_t lv_tag, uint8_t lv_tag2);
++/* take a master (src) tlvdev and fill up all empty slots in 'dst' */
++void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src);
++
++#define TLVP_PRESENT(x, y)    ((x)->lv[y].val)
++#define TLVP_LEN(x, y)                (x)->lv[y].len
++#define TLVP_VAL(x, y)                (x)->lv[y].val
++
++#endif /* _TLV_H */
index 0000000,0000000..198f45a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#ifndef OSMOCORE_UTIL_H
++#define OSMOCORE_UTIL_H
++
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++#endif
index 0000000,0000000..7c29869
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++libdir=@libdir@
++includedir=@includedir@
++
++Name: Osmocom Core Library
++Description: C Utility Library
++Version: @VERSION@
++Libs: -L${libdir} -losmocore
++Cflags: -I${includedir}/
++
index 0000000,0000000..b82b6fb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++# This is _NOT_ the library release version, it's an API version.
++# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
++LIBVERSION=0:0:0
++
++INCLUDES = $(all_includes) -I$(top_srcdir)/include
++AM_CFLAGS = -fPIC -Wall
++
++lib_LTLIBRARIES = libosmocore.la
++
++libosmocore_la_SOURCES = msgb.c timer.c talloc.c select.c signal.c \
++                       tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c
index 0000000,0000000..235c3ce
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,170 @@@
++/* bit vector utility routines */
++
++/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++
++#include <errno.h>
++#include <stdint.h>
++
++#include <osmocore/bitvec.h>
++
++#define BITNUM_FROM_COMP(byte, bit)   ((byte*8)+bit)
++
++static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
++{
++      unsigned int bytenum = bitnum / 8;
++
++      return bytenum;
++}
++
++/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
++static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
++{
++      int bitval;
++
++      switch (bit) {
++      case ZERO:
++              bitval = (0 << bitnum);
++              break;
++      case ONE:
++              bitval = (1 << bitnum);
++              break;
++      case L:
++              bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
++              break;
++      case H:
++              bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
++              break;
++      default:
++              return 0;
++      }
++      return bitval;
++}
++
++/* check if the bit is 0 or 1 for a given position inside a bitvec */
++enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr)
++{
++      unsigned int bytenum = bytenum_from_bitnum(bitnr);
++      unsigned int bitnum = 7 - (bitnr % 8);
++      uint8_t bitval;
++
++      if (bytenum >= bv->data_len)
++              return -EINVAL;
++
++      bitval = bitval2mask(ONE, bitnum);
++
++      if (bv->data[bytenum] & bitval)
++              return ONE;
++
++      return ZERO;
++}
++
++/* get the Nth set bit inside the bit vector */
++unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n)
++{
++      unsigned int i, k = 0;
++
++      for (i = 0; i < bv->data_len*8; i++) {
++              if (bitvec_get_bit_pos(bv, i) == ONE) {
++                      k++;
++                      if (k == n)
++                              return i;
++              }
++      }
++
++      return 0;
++}
++
++/* set the bit at a given position inside a bitvec */
++int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
++                      enum bit_value bit)
++{
++      unsigned int bytenum = bytenum_from_bitnum(bitnr);
++      unsigned int bitnum = 7 - (bitnr % 8);
++      uint8_t bitval;
++
++      if (bytenum >= bv->data_len)
++              return -EINVAL;
++
++      /* first clear the bit */
++      bitval = bitval2mask(ONE, bitnum);
++      bv->data[bytenum] &= ~bitval;
++
++      /* then set it to desired value */
++      bitval = bitval2mask(bit, bitnum);
++      bv->data[bytenum] |= bitval;
++
++      return 0;
++}
++
++/* set the next bit inside a bitvec */
++int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
++{
++      int rc;
++
++      rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
++      if (!rc)
++              bv->cur_bit++;
++
++      return rc;
++}
++
++/* set multiple bits (based on array of bitvals) at current pos */
++int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count)
++{
++      int i, rc;
++
++      for (i = 0; i < count; i++) {
++              rc = bitvec_set_bit(bv, bits[i]);
++              if (rc)
++                      return rc;
++      }
++
++      return 0;
++}
++
++/* set multiple bits (based on numeric value) at current pos */
++int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits)
++{
++      int i, rc;
++
++      for (i = 0; i < num_bits; i++) {
++              int bit = 0;
++              if (ui & (1 << (num_bits - i - 1)))
++                      bit = 1;
++              rc = bitvec_set_bit(bv, bit);
++              if (rc)
++                      return rc;
++      }
++
++      return 0;
++}
++
++/* pad all remaining bits up to num_bits */
++int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
++{
++      unsigned int i;
++
++      for (i = bv->cur_bit; i <= up_to_bit; i++)
++              bitvec_set_bit(bv, L);
++
++      return 0;
++}
index 0000000,0000000..5d5680c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,230 @@@
++/*
++ * COMP128 implementation
++ *
++ *
++ * This code is inspired by original code from :
++ *  Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>,
++ *  and David Wagner <daw@cs.berkeley.edu>
++ *
++ * But it has been fully rewritten from various PDFs found online describing
++ * the algorithm because the licence of the code referenced above was unclear.
++ * A comment snippet from the original code is included below, it describes
++ * where the doc came from and how the algorithm was reverse engineered.
++ *
++ *
++ * (C) 2009 by Sylvain Munaut <tnt@246tNt.com>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++/*
++ * --- SNIP ---
++ *
++ * This code derived from a leaked document from the GSM standards.
++ * Some missing pieces were filled in by reverse-engineering a working SIM.
++ * We have verified that this is the correct COMP128 algorithm.
++ *
++ * The first page of the document identifies it as
++ *    _Technical Information: GSM System Security Study_.
++ *    10-1617-01, 10th June 1988.
++ * The bottom of the title page is marked
++ *    Racal Research Ltd.
++ *    Worton Drive, Worton Grange Industrial Estate,
++ *    Reading, Berks. RG2 0SB, England.
++ *    Telephone: Reading (0734) 868601   Telex: 847152
++ * The relevant bits are in Part I, Section 20 (pages 66--67).  Enjoy!
++ *
++ * Note: There are three typos in the spec (discovered by
++ * reverse-engineering).
++ * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read
++ * "z = (2 * x[m] + x[n]) mod 2^(9-j)".
++ * Second, the "k" loop in the "Form bits from bytes" section is severely
++ * botched: the k index should run only from 0 to 3, and clearly the range
++ * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8,
++ * to be consistent with the subsequent section).
++ * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as
++ * claimed in the document.  (And the document doesn't specify how Kc is
++ * derived, but that was also easily discovered with reverse engineering.)
++ * All of these typos have been corrected in the following code.
++ *
++ * --- /SNIP ---
++ */
++
++#include <string.h>
++#include <stdint.h>
++
++/* The compression tables (just copied ...) */
++static const uint8_t table_0[512] = {
++ 102, 177, 186, 162,   2, 156, 112,  75,  55,  25,   8,  12, 251, 193, 246, 188,
++ 109, 213, 151,  53,  42,  79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161,
++ 252,  37, 244,  47,  64, 211,   6, 237, 185, 160, 139, 113,  76, 138,  59,  70,
++  67,  26,  13, 157,  63, 179, 221,  30, 214,  36, 166,  69, 152, 124, 207, 116,
++ 247, 194,  41,  84,  71,   1,  49,  14,  95,  35, 169,  21,  96,  78, 215, 225,
++ 182, 243,  28,  92, 201, 118,   4,  74, 248, 128,  17,  11, 146, 132, 245,  48,
++ 149,  90, 120,  39,  87, 230, 106, 232, 175,  19, 126, 190, 202, 141, 137, 176,
++ 250,  27, 101,  40, 219, 227,  58,  20,  51, 178,  98, 216, 140,  22,  32, 121,
++  61, 103, 203,  72,  29, 110,  85, 212, 180, 204, 150, 183,  15,  66, 172, 196,
++  56, 197, 158,   0, 100,  45, 153,   7, 144, 222, 163, 167,  60, 135, 210, 231,
++ 174, 165,  38, 249, 224,  34, 220, 229, 217, 208, 241,  68, 206, 189, 125, 255,
++ 239,  54, 168,  89, 123, 122,  73, 145, 117, 234, 143,  99, 129, 200, 192,  82,
++ 104, 170, 136, 235,  93,  81, 205, 173, 236,  94, 105,  52,  46, 228, 198,   5,
++  57, 254,  97, 155, 142, 133, 199, 171, 187,  50,  65, 181, 127, 107, 147, 226,
++ 184, 218, 131,  33,  77,  86,  31,  44,  88,  62, 238,  18,  24,  43, 154,  23,
++  80, 159, 134, 111,   9, 114,   3,  91,  16, 130,  83,  10, 195, 240, 253, 119,
++ 177, 102, 162, 186, 156,   2,  75, 112,  25,  55,  12,   8, 193, 251, 188, 246,
++ 213, 109,  53, 151,  79,  42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108,
++  37, 252,  47, 244, 211,  64, 237,   6, 160, 185, 113, 139, 138,  76,  70,  59,
++  26,  67, 157,  13, 179,  63,  30, 221,  36, 214,  69, 166, 124, 152, 116, 207,
++ 194, 247,  84,  41,   1,  71,  14,  49,  35,  95,  21, 169,  78,  96, 225, 215,
++ 243, 182,  92,  28, 118, 201,  74,   4, 128, 248,  11,  17, 132, 146,  48, 245,
++  90, 149,  39, 120, 230,  87, 232, 106,  19, 175, 190, 126, 141, 202, 176, 137,
++  27, 250,  40, 101, 227, 219,  20,  58, 178,  51, 216,  98,  22, 140, 121,  32,
++ 103,  61,  72, 203, 110,  29, 212,  85, 204, 180, 183, 150,  66,  15, 196, 172,
++ 197,  56,   0, 158,  45, 100,   7, 153, 222, 144, 167, 163, 135,  60, 231, 210,
++ 165, 174, 249,  38,  34, 224, 229, 220, 208, 217,  68, 241, 189, 206, 255, 125,
++  54, 239,  89, 168, 122, 123, 145,  73, 234, 117,  99, 143, 200, 129,  82, 192,
++ 170, 104, 235, 136,  81,  93, 173, 205,  94, 236,  52, 105, 228,  46,   5, 198,
++ 254,  57, 155,  97, 133, 142, 171, 199,  50, 187, 181,  65, 107, 127, 226, 147,
++ 218, 184,  33, 131,  86,  77,  44,  31,  62,  88,  18, 238,  43,  24,  23, 154,
++ 159,  80, 111, 134, 114,   9,  91,   3, 130,  16,  10,  83, 240, 195, 119, 253,
++}, table_1[256] = {
++  19,  11,  80, 114,  43,   1,  69,  94,  39,  18, 127, 117,  97,   3,  85,  43,
++  27, 124,  70,  83,  47,  71,  63,  10,  47,  89,  79,   4,  14,  59,  11,   5,
++  35, 107, 103,  68,  21,  86,  36,  91,  85, 126,  32,  50, 109,  94, 120,   6,
++  53,  79,  28,  45,  99,  95,  41,  34,  88,  68,  93,  55, 110, 125, 105,  20,
++  90,  80,  76,  96,  23,  60,  89,  64, 121,  56,  14,  74, 101,   8,  19,  78,
++  76,  66, 104,  46, 111,  50,  32,   3,  39,   0,  58,  25,  92,  22,  18,  51,
++  57,  65, 119, 116,  22, 109,   7,  86,  59,  93,  62, 110,  78,  99,  77,  67,
++  12, 113,  87,  98, 102,   5,  88,  33,  38,  56,  23,   8,  75,  45,  13,  75,
++  95,  63,  28,  49, 123, 120,  20, 112,  44,  30,  15,  98, 106,   2, 103,  29,
++  82, 107,  42, 124,  24,  30,  41,  16, 108, 100, 117,  40,  73,  40,   7, 114,
++  82, 115,  36, 112,  12, 102, 100,  84,  92,  48,  72,  97,   9,  54,  55,  74,
++ 113, 123,  17,  26,  53,  58,   4,   9,  69, 122,  21, 118,  42,  60,  27,  73,
++ 118, 125,  34,  15,  65, 115,  84,  64,  62,  81,  70,   1,  24, 111, 121,  83,
++ 104,  81,  49, 127,  48, 105,  31,  10,   6,  91,  87,  37,  16,  54, 116, 126,
++  31,  38,  13,   0,  72, 106,  77,  61,  26,  67,  46,  29,  96,  37,  61,  52,
++ 101,  17,  44, 108,  71,  52,  66,  57,  33,  51,  25,  90,   2, 119, 122,  35,
++}, table_2[128] = {
++ 52,  50,  44,   6,  21,  49,  41,  59,  39,  51,  25,  32,  51,  47,  52,  43,
++ 37,   4,  40,  34,  61,  12,  28,   4,  58,  23,   8,  15,  12,  22,   9,  18,
++ 55,  10,  33,  35,  50,   1,  43,   3,  57,  13,  62,  14,   7,  42,  44,  59,
++ 62,  57,  27,   6,   8,  31,  26,  54,  41,  22,  45,  20,  39,   3,  16,  56,
++ 48,   2,  21,  28,  36,  42,  60,  33,  34,  18,   0,  11,  24,  10,  17,  61,
++ 29,  14,  45,  26,  55,  46,  11,  17,  54,  46,   9,  24,  30,  60,  32,   0,
++ 20,  38,   2,  30,  58,  35,   1,  16,  56,  40,  23,  48,  13,  19,  19,  27,
++ 31,  53,  47,  38,  63,  15,  49,   5,  37,  53,  25,  36,  63,  29,   5,   7,
++}, table_3[64] = {
++  1,   5,  29,   6,  25,   1,  18,  23,  17,  19,   0,   9,  24,  25,   6,  31,
++ 28,  20,  24,  30,   4,  27,   3,  13,  15,  16,  14,  18,   4,   3,   8,   9,
++ 20,   0,  12,  26,  21,   8,  28,   2,  29,   2,  15,   7,  11,  22,  14,  10,
++ 17,  21,  12,  30,  26,  27,  16,  31,  11,   7,  13,  23,  10,   5,  22,  19,
++}, table_4[32] = {
++ 15,  12,  10,   4,   1,  14,  11,   7,   5,   0,  14,   7,   1,   2,  13,   8,
++ 10,   3,   4,   9,   6,   0,   3,   2,   5,   6,   8,   9,  11,  13,  15,  12,
++};
++
++static const uint8_t *_comp128_table[5] = { table_0, table_1, table_2, table_3, table_4 };
++
++
++static inline void
++_comp128_compression_round(uint8_t *x, int n, const uint8_t *tbl)
++{
++      int i, j, m, a, b, y, z;
++      m = 4 - n;
++      for (i=0; i<(1<<n); i++)
++              for (j=0; j<(1<<m); j++) {
++                      a = j + i * (2<<m);
++                      b = a + (1<<m);
++                      y = (x[a] + (x[b]<<1)) & ((32<<m)-1);
++                      z = ((x[a]<<1) + x[b]) & ((32<<m)-1);
++                      x[a] = tbl[y];
++                      x[b] = tbl[z];
++              }
++}
++
++static inline void
++_comp128_compression(uint8_t *x)
++{
++      int n;
++      for (n=0; n<5; n++)
++              _comp128_compression_round(x, n, _comp128_table[n]);
++}
++
++static inline void
++_comp128_bitsfrombytes(uint8_t *x, uint8_t *bits)
++{
++      int i;
++      memset(bits, 0x00, 128);
++      for (i=0; i<128; i++)
++              if (x[i>>2] & (1<<(3-(i&3))))
++                      bits[i] = 1;
++}
++
++static inline void
++_comp128_permutation(uint8_t *x, uint8_t *bits)
++{
++      int i;
++      memset(&x[16], 0x00, 16);
++      for (i=0; i<128; i++)
++              x[(i>>3)+16] |= bits[(i*17) & 127] << (7-(i&7));
++}
++
++void
++comp128(uint8_t *ki, uint8_t *rand, uint8_t *sres, uint8_t *kc)
++{
++      int i;
++      uint8_t x[32], bits[128];
++
++      /* x[16-31] = RAND */
++      memcpy(&x[16], rand, 16);
++
++      /* Round 1-7 */
++      for (i=0; i<7; i++) {
++              /* x[0-15] = Ki */
++              memcpy(x, ki, 16);
++
++              /* Compression */
++              _comp128_compression(x);
++
++              /* FormBitFromBytes */
++              _comp128_bitsfrombytes(x, bits);
++
++              /* Permutation */
++              _comp128_permutation(x, bits);
++      }
++
++      /* Round 8 (final) */
++              /* x[0-15] = Ki */
++      memcpy(x, ki, 16);
++
++              /* Compression */
++      _comp128_compression(x);
++
++      /* Output stage */
++      for (i=0; i<8; i+=2)
++              sres[i>>1] = x[i]<<4 | x[i+1];
++
++      for (i=0; i<12; i+=2)
++              kc[i>>1] = (x[i + 18] << 6) |
++                         (x[i + 19] << 2) |
++                         (x[i + 20] >> 2);
++
++      kc[6] = (x[30]<<6) | (x[31]<<2);
++      kc[7] = 0;
++}
++
index 0000000,0000000..b0a66a6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,215 @@@
++/*
++ * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
++ * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
++ * (C) 2009 by Harald Welte <laforge@gnumonks.org>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++//#include <openbsc/gsm_data.h>
++#include <osmocore/utils.h>
++#include <osmocore/gsm_utils.h>
++
++#include <stdlib.h>
++#include <stdint.h>
++#include <string.h>
++#include <stdio.h>
++#include <errno.h>
++
++#include "../config.h"
++
++/* GSM 03.38 6.2.1 Charachter packing */
++int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length)
++{
++      int i = 0;
++      int l = 0;
++
++        /* FIXME: We need to account for user data headers here */
++      i += l;
++      for (; i < length; i ++)
++              *(text ++) =
++                      ((user_data[(i * 7 + 7) >> 3] <<
++                        (7 - ((i * 7 + 7) & 7))) |
++                       (user_data[(i * 7) >> 3] >>
++                        ((i * 7) & 7))) & 0x7f;
++      *text = '\0';
++
++      return i - l;
++}
++
++
++/* GSM 03.38 6.2.1 Charachter packing */
++int gsm_7bit_encode(uint8_t *result, const char *data)
++{
++      int i,j = 0;
++      unsigned char ch1, ch2;
++      int shift = 0;
++
++      for ( i=0; i<strlen(data); i++ ) {
++
++              ch1 = data[i] & 0x7F;
++              ch1 = ch1 >> shift;
++              ch2 = data[(i+1)] & 0x7F;
++              ch2 = ch2 << (7-shift);
++
++              ch1 = ch1 | ch2;
++
++              result[j++] = ch1;
++
++              shift++;
++
++              if ((shift == 7) && (i+1<strlen(data))) {
++                      shift = 0;
++                      i++;
++              }
++      }
++
++      return i;
++}
++
++/* determine power control level for given dBm value, as indicated
++ * by the tables in chapter 4.1.1 of GSM TS 05.05 */
++int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
++{
++      switch (band) {
++      case GSM_BAND_450:
++      case GSM_BAND_480:
++      case GSM_BAND_750:
++      case GSM_BAND_900:
++      case GSM_BAND_810:
++      case GSM_BAND_850:
++              if (dbm >= 39)
++                      return 0;
++              else if (dbm < 5)
++                      return 19;
++              else {
++                      /* we are guaranteed to have (5 <= dbm < 39) */
++                      return 2 + ((39 - dbm) / 2);
++              }
++              break;
++      case GSM_BAND_1800:
++              if (dbm >= 36)
++                      return 29;
++              else if (dbm >= 34)     
++                      return 30;
++              else if (dbm >= 32)
++                      return 31;
++              else if (dbm == 31)
++                      return 0;
++              else {
++                      /* we are guaranteed to have (0 <= dbm < 31) */
++                      return (30 - dbm) / 2;
++              }
++              break;
++      case GSM_BAND_1900:
++              if (dbm >= 33)
++                      return 30;
++              else if (dbm >= 32)
++                      return 31;
++              else if (dbm == 31)
++                      return 0;
++              else {
++                      /* we are guaranteed to have (0 <= dbm < 31) */
++                      return (30 - dbm) / 2;
++              }
++              break;
++      }
++      return -EINVAL;
++}
++
++int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
++{
++      lvl &= 0x1f;
++
++      switch (band) {
++      case GSM_BAND_450:
++      case GSM_BAND_480:
++      case GSM_BAND_750:
++      case GSM_BAND_900:
++      case GSM_BAND_810:
++      case GSM_BAND_850:
++              if (lvl < 2)
++                      return 39;
++              else if (lvl < 20)
++                      return 39 - ((lvl - 2) * 2) ;
++              else
++                      return 5;
++              break;
++      case GSM_BAND_1800:
++              if (lvl < 16)
++                      return 30 - (lvl * 2);
++              else if (lvl < 29)
++                      return 0;
++              else
++                      return 36 - ((lvl - 29) * 2);
++              break;
++      case GSM_BAND_1900:
++              if (lvl < 16)
++                      return 30 - (lvl * 2);
++              else if (lvl < 30)
++                      return -EINVAL;
++              else
++                      return 33 - (lvl - 30);
++              break;
++      }
++      return -EINVAL;
++}
++
++/* According to TS 08.05 Chapter 8.1.4 */
++int rxlev2dbm(uint8_t rxlev)
++{
++      if (rxlev > 63)
++              rxlev = 63;
++
++      return -110 + rxlev;
++}
++
++/* According to TS 08.05 Chapter 8.1.4 */
++uint8_t dbm2rxlev(int dbm)
++{
++      int rxlev = dbm + 110;
++
++      if (rxlev > 63)
++              rxlev = 63;
++      else if (rxlev < 0)
++              rxlev = 0;
++
++      return rxlev;
++}
++
++#ifdef HAVE_EXECINFO_H
++#include <execinfo.h>
++void generate_backtrace()
++{
++      int i, nptrs;
++      void *buffer[100];
++      char **strings;
++
++      nptrs = backtrace(buffer, ARRAY_SIZE(buffer));
++      printf("backtrace() returned %d addresses\n", nptrs);
++
++      strings = backtrace_symbols(buffer, nptrs);
++      if (!strings)
++              return;
++
++      for (i = 1; i < nptrs; i++)
++              printf("%s\n", strings[i]);
++
++      free(strings);
++}
++#endif
index 0000000,0000000..2521ca8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,98 @@@
++/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++
++#include <unistd.h>
++#include <string.h>
++#include <stdlib.h>
++#include <sys/types.h>
++
++#include <osmocore/msgb.h>
++//#include <openbsc/gsm_data.h>
++#include <osmocore/talloc.h>
++//#include <openbsc/debug.h>
++
++void *tall_msgb_ctx;
++
++struct msgb *msgb_alloc(uint16_t size, const char *name)
++{
++      struct msgb *msg;
++
++      msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name);
++
++      if (!msg) {
++              //LOGP(DRSL, LOGL_FATAL, "unable to allocate msgb\n");
++              return NULL;
++      }
++
++      msg->data_len = size;
++      msg->len = 0;
++      msg->data = msg->_data;
++
++      msg->head = msg->data;
++      msg->data = msg->data;
++      /* reset tail pointer */
++      msg->tail = msg->data;
++      //msg->end = msg->tail + size;
++
++      return msg;
++}
++
++void msgb_free(struct msgb *m)
++{
++      talloc_free(m);
++}
++
++void msgb_enqueue(struct llist_head *queue, struct msgb *msg)
++{
++      llist_add_tail(&msg->list, queue);
++}
++
++struct msgb *msgb_dequeue(struct llist_head *queue)
++{
++      struct llist_head *lh;
++
++      if (llist_empty(queue))
++              return NULL;
++
++      lh = queue->next;
++      llist_del(lh);
++      
++      return llist_entry(lh, struct msgb, list);
++}
++
++void msgb_reset(struct msgb *msg)
++{
++      msg->len = 0;
++      msg->len = 0;
++      msg->data = msg->_data;
++
++      msg->head = msg->data;
++      msg->data = msg->data;
++      /* reset tail pointer */
++      msg->tail = msg->data;
++
++      /* reset pointers */
++      msg->bts_link = NULL;
++      msg->trx = NULL;
++      msg->lchan = NULL;
++      msg->l2h = NULL;
++      msg->l3h = NULL;
++      msg->smsh = NULL;
++}
index 0000000,0000000..4f5d7ed
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,128 @@@
++/* select filedescriptor handling, taken from:
++ * userspace logging daemon for the iptables ULOG target
++ * of the linux 2.4 netfilter subsystem.
++ *
++ * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org>
++ *
++ *  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
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <fcntl.h>
++#include <osmocore/select.h>
++#include <osmocore/linuxlist.h>
++#include <osmocore/timer.h>
++
++#ifdef HAVE_SYS_SELECT_H
++
++static int maxfd = 0;
++static LLIST_HEAD(bsc_fds);
++static int unregistered_count;
++
++int bsc_register_fd(struct bsc_fd *fd)
++{
++      int flags;
++
++      /* make FD nonblocking */
++      flags = fcntl(fd->fd, F_GETFL);
++      if (flags < 0)
++              return flags;
++      flags |= O_NONBLOCK;
++      flags = fcntl(fd->fd, F_SETFL, flags);
++      if (flags < 0)
++              return flags;
++
++      /* Register FD */
++      if (fd->fd > maxfd)
++              maxfd = fd->fd;
++
++      llist_add_tail(&fd->list, &bsc_fds);
++
++      return 0;
++}
++
++void bsc_unregister_fd(struct bsc_fd *fd)
++{
++      unregistered_count++;
++      llist_del(&fd->list);
++}
++
++int bsc_select_main(int polling)
++{
++      struct bsc_fd *ufd, *tmp;
++      fd_set readset, writeset, exceptset;
++      int work = 0, rc;
++      struct timeval no_time = {0, 0};
++
++      FD_ZERO(&readset);
++      FD_ZERO(&writeset);
++      FD_ZERO(&exceptset);
++
++      /* prepare read and write fdsets */
++      llist_for_each_entry(ufd, &bsc_fds, list) {
++              if (ufd->when & BSC_FD_READ)
++                      FD_SET(ufd->fd, &readset);
++
++              if (ufd->when & BSC_FD_WRITE)
++                      FD_SET(ufd->fd, &writeset);
++
++              if (ufd->when & BSC_FD_EXCEPT)
++                      FD_SET(ufd->fd, &exceptset);
++      }
++
++      bsc_timer_check();
++
++      if (!polling)
++              bsc_prepare_timers();
++      rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer());
++      if (rc < 0)
++              return 0;
++
++      /* fire timers */
++      bsc_update_timers();
++
++      /* call registered callback functions */
++restart:
++      unregistered_count = 0;
++      llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) {
++              int flags = 0;
++
++              if (FD_ISSET(ufd->fd, &readset)) {
++                      flags |= BSC_FD_READ;
++                      FD_CLR(ufd->fd, &readset);
++              }
++
++              if (FD_ISSET(ufd->fd, &writeset)) {
++                      flags |= BSC_FD_WRITE;
++                      FD_CLR(ufd->fd, &writeset);
++              }
++
++              if (FD_ISSET(ufd->fd, &exceptset)) {
++                      flags |= BSC_FD_EXCEPT;
++                      FD_CLR(ufd->fd, &exceptset);
++              }
++
++              if (flags) {
++                      work = 1;
++                      ufd->cb(ufd, flags);
++              }
++              /* ugly, ugly hack. If more than one filedescriptors were
++               * unregistered, they might have been consecutive and
++               * llist_for_each_entry_safe() is no longer safe */
++              if (unregistered_count > 1)
++                      goto restart;
++      }
++      return work;
++}
++
++#endif /* _HAVE_SYS_SELECT_H */
index 0000000,0000000..c7ca86c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,84 @@@
++/* Generic signalling/notification infrastructure */
++/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <osmocore/signal.h>
++#include <osmocore/talloc.h>
++#include <osmocore/linuxlist.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++
++void *tall_sigh_ctx;
++static LLIST_HEAD(signal_handler_list);
++
++struct signal_handler {
++      struct llist_head entry;
++      unsigned int subsys;
++      signal_cbfn *cbfn;
++      void *data;
++};
++
++
++int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
++{
++      struct signal_handler *sig_data;
++
++      sig_data = talloc(tall_sigh_ctx, struct signal_handler);
++      if (!sig_data)
++              return -ENOMEM;
++
++      memset(sig_data, 0, sizeof(*sig_data));
++
++      sig_data->subsys = subsys;
++      sig_data->data = data;
++      sig_data->cbfn = cbfn;
++
++      /* FIXME: check if we already have a handler for this subsys/cbfn/data */
++
++      llist_add_tail(&sig_data->entry, &signal_handler_list);
++
++      return 0;
++}
++
++void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
++{
++      struct signal_handler *handler;
++
++      llist_for_each_entry(handler, &signal_handler_list, entry) {
++              if (handler->cbfn == cbfn && handler->data == data 
++                  && subsys == handler->subsys) {
++                      llist_del(&handler->entry);
++                      talloc_free(handler);
++                      break;
++              }
++      }
++}
++
++
++void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data)
++{
++      struct signal_handler *handler;
++
++      llist_for_each_entry(handler, &signal_handler_list, entry) {
++              if (handler->subsys != subsys)
++                      continue;
++              (*handler->cbfn)(subsys, signal, handler->data, signal_data);
++      }
++}
index 0000000,0000000..34e6a40
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,66 @@@
++/* utility routines for keeping some statistics */
++
++/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++
++#include <sys/types.h>
++
++#include <osmocore/linuxlist.h>
++#include <osmocore/talloc.h>
++#include <osmocore/statistics.h>
++
++static LLIST_HEAD(counters);
++
++void *tall_ctr_ctx;
++
++struct counter *counter_alloc(const char *name)
++{
++      struct counter *ctr = talloc_zero(tall_ctr_ctx, struct counter);
++
++      if (!ctr)
++              return NULL;
++
++      ctr->name = name;
++      llist_add_tail(&ctr->list, &counters);
++
++      return ctr;
++}
++
++void counter_free(struct counter *ctr)
++{
++      llist_del(&ctr->list);
++      talloc_free(ctr);
++}
++
++int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data)
++{
++      struct counter *ctr;
++      int rc = 0;
++
++      llist_for_each_entry(ctr, &counters, list) {
++              rc = handle_counter(ctr, data);
++              if (rc < 0)
++                      return rc;
++      }
++
++      return rc;
++}
++
index 0000000,0000000..98c2ee0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1805 @@@
++/* 
++   Samba Unix SMB/CIFS implementation.
++
++   Samba trivial allocation library - new interface
++
++   NOTE: Please read talloc_guide.txt for full documentation
++
++   Copyright (C) Andrew Tridgell 2004
++   Copyright (C) Stefan Metzmacher 2006
++   
++     ** NOTE! The following LGPL license applies to the talloc
++     ** library. This does NOT imply that all of Samba is released
++     ** under the LGPL
++   
++   This library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 3 of the License, or (at your option) any later version.
++
++   This library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with this library; if not, see <http://www.gnu.org/licenses/>.
++*/
++
++/*
++  inspired by http://swapped.cc/halloc/
++*/
++
++#ifdef _SAMBA_BUILD_
++#include "version.h"
++#if (SAMBA_VERSION_MAJOR<4)
++#include "includes.h"
++/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file
++ * we trust ourselves... */
++#ifdef malloc
++#undef malloc
++#endif
++#ifdef realloc
++#undef realloc
++#endif
++#define _TALLOC_SAMBA3
++#endif /* (SAMBA_VERSION_MAJOR<4) */
++#endif /* _SAMBA_BUILD_ */
++
++#ifndef _TALLOC_SAMBA3
++//#include "replace.h"
++#include <sys/types.h>
++#include <unistd.h>
++#include <stdio.h>
++#include <stdbool.h>
++#define __USE_GNU
++#include <string.h>
++#undef __USE_GNU
++#include <osmocore/talloc.h>
++#define MIN(x,y) ((x) < (y) ? (x) : (y))
++#endif /* not _TALLOC_SAMBA3 */
++
++/* use this to force every realloc to change the pointer, to stress test
++   code that might not cope */
++#define ALWAYS_REALLOC 0
++
++
++#define MAX_TALLOC_SIZE 0x10000000
++#define TALLOC_MAGIC 0xe814ec70
++#define TALLOC_FLAG_FREE 0x01
++#define TALLOC_FLAG_LOOP 0x02
++#define TALLOC_FLAG_POOL 0x04         /* This is a talloc pool */
++#define TALLOC_FLAG_POOLMEM 0x08      /* This is allocated in a pool */
++#define TALLOC_MAGIC_REFERENCE ((const char *)1)
++
++/* by default we abort when given a bad pointer (such as when talloc_free() is called 
++   on a pointer that came from malloc() */
++#ifndef TALLOC_ABORT
++#define TALLOC_ABORT(reason) abort()
++#endif
++
++#ifndef discard_const_p
++#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
++# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr)))
++#else
++# define discard_const_p(type, ptr) ((type *)(ptr))
++#endif
++#endif
++
++/* these macros gain us a few percent of speed on gcc */
++#if (__GNUC__ >= 3)
++/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1
++   as its first argument */
++#ifndef likely
++#define likely(x)   __builtin_expect(!!(x), 1)
++#endif
++#ifndef unlikely
++#define unlikely(x) __builtin_expect(!!(x), 0)
++#endif
++#else
++#ifndef likely
++#define likely(x) (x)
++#endif
++#ifndef unlikely
++#define unlikely(x) (x)
++#endif
++#endif
++
++#ifdef __APPLE__
++/* taken from http://insanecoding.blogspot.com/2007/03/methods-for-safe-string-handling.html */
++size_t strnlen(const char *s, size_t n)
++{
++  const char *p = (const char *)memchr(s, 0, n);
++  return(p ? p-s : n);
++}
++#endif
++
++/* this null_context is only used if talloc_enable_leak_report() or
++   talloc_enable_leak_report_full() is called, otherwise it remains
++   NULL
++*/
++static void *null_context;
++static void *autofree_context;
++
++struct talloc_reference_handle {
++      struct talloc_reference_handle *next, *prev;
++      void *ptr;
++};
++
++typedef int (*talloc_destructor_t)(void *);
++
++struct talloc_chunk {
++      struct talloc_chunk *next, *prev;
++      struct talloc_chunk *parent, *child;
++      struct talloc_reference_handle *refs;
++      talloc_destructor_t destructor;
++      const char *name;
++      size_t size;
++      unsigned flags;
++
++      /*
++       * "pool" has dual use:
++       *
++       * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool"
++       * marks the end of the currently allocated area.
++       *
++       * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool"
++       * is a pointer to the struct talloc_chunk of the pool that it was
++       * allocated from. This way children can quickly find the pool to chew
++       * from.
++       */
++      void *pool;
++};
++
++/* 16 byte alignment seems to keep everyone happy */
++#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
++#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
++
++static void (*talloc_abort_fn)(const char *reason);
++
++void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
++{
++      talloc_abort_fn = abort_fn;
++}
++
++static void talloc_abort(const char *reason)
++{
++      if (!talloc_abort_fn) {
++              TALLOC_ABORT(reason);
++      }
++
++      talloc_abort_fn(reason);
++}
++
++static void talloc_abort_double_free(void)
++{
++      talloc_abort("Bad talloc magic value - double free");
++}
++
++static void talloc_abort_unknown_value(void)
++{
++      talloc_abort("Bad talloc magic value - unknown value");
++}
++
++/* panic if we get a bad magic value */
++static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
++{
++      const char *pp = (const char *)ptr;
++      struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
++      if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~0xF)) != TALLOC_MAGIC)) { 
++              if (tc->flags & TALLOC_FLAG_FREE) {
++                      talloc_abort_double_free();
++              } else {
++                      talloc_abort_unknown_value();
++              }
++      }
++      return tc;
++}
++
++/* hook into the front of the list */
++#define _TLIST_ADD(list, p) \
++do { \
++        if (!(list)) { \
++              (list) = (p); \
++              (p)->next = (p)->prev = NULL; \
++      } else { \
++              (list)->prev = (p); \
++              (p)->next = (list); \
++              (p)->prev = NULL; \
++              (list) = (p); \
++      }\
++} while (0)
++
++/* remove an element from a list - element doesn't have to be in list. */
++#define _TLIST_REMOVE(list, p) \
++do { \
++      if ((p) == (list)) { \
++              (list) = (p)->next; \
++              if (list) (list)->prev = NULL; \
++      } else { \
++              if ((p)->prev) (p)->prev->next = (p)->next; \
++              if ((p)->next) (p)->next->prev = (p)->prev; \
++      } \
++      if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
++} while (0)
++
++
++/*
++  return the parent chunk of a pointer
++*/
++static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
++{
++      struct talloc_chunk *tc;
++
++      if (unlikely(ptr == NULL)) {
++              return NULL;
++      }
++
++      tc = talloc_chunk_from_ptr(ptr);
++      while (tc->prev) tc=tc->prev;
++
++      return tc->parent;
++}
++
++void *talloc_parent(const void *ptr)
++{
++      struct talloc_chunk *tc = talloc_parent_chunk(ptr);
++      return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
++}
++
++/*
++  find parents name
++*/
++const char *talloc_parent_name(const void *ptr)
++{
++      struct talloc_chunk *tc = talloc_parent_chunk(ptr);
++      return tc? tc->name : NULL;
++}
++
++/*
++  A pool carries an in-pool object count count in the first 16 bytes.
++  bytes. This is done to support talloc_steal() to a parent outside of the
++  pool. The count includes the pool itself, so a talloc_free() on a pool will
++  only destroy the pool if the count has dropped to zero. A talloc_free() of a
++  pool member will reduce the count, and eventually also call free(3) on the
++  pool memory.
++
++  The object count is not put into "struct talloc_chunk" because it is only
++  relevant for talloc pools and the alignment to 16 bytes would increase the
++  memory footprint of each talloc chunk by those 16 bytes.
++*/
++
++#define TALLOC_POOL_HDR_SIZE 16
++
++static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc)
++{
++      return (unsigned int *)((char *)tc + sizeof(struct talloc_chunk));
++}
++
++/*
++  Allocate from a pool
++*/
++
++static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,
++                                            size_t size)
++{
++      struct talloc_chunk *pool_ctx = NULL;
++      size_t space_left;
++      struct talloc_chunk *result;
++      size_t chunk_size;
++
++      if (parent == NULL) {
++              return NULL;
++      }
++
++      if (parent->flags & TALLOC_FLAG_POOL) {
++              pool_ctx = parent;
++      }
++      else if (parent->flags & TALLOC_FLAG_POOLMEM) {
++              pool_ctx = (struct talloc_chunk *)parent->pool;
++      }
++
++      if (pool_ctx == NULL) {
++              return NULL;
++      }
++
++      space_left = ((char *)pool_ctx + TC_HDR_SIZE + pool_ctx->size)
++              - ((char *)pool_ctx->pool);
++
++      /*
++       * Align size to 16 bytes
++       */
++      chunk_size = ((size + 15) & ~15);
++
++      if (space_left < chunk_size) {
++              return NULL;
++      }
++
++      result = (struct talloc_chunk *)pool_ctx->pool;
++
++#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED)
++      VALGRIND_MAKE_MEM_UNDEFINED(result, size);
++#endif
++
++      pool_ctx->pool = (void *)((char *)result + chunk_size);
++
++      result->flags = TALLOC_MAGIC | TALLOC_FLAG_POOLMEM;
++      result->pool = pool_ctx;
++
++      *talloc_pool_objectcount(pool_ctx) += 1;
++
++      return result;
++}
++
++/* 
++   Allocate a bit of memory as a child of an existing pointer
++*/
++static inline void *__talloc(const void *context, size_t size)
++{
++      struct talloc_chunk *tc = NULL;
++
++      if (unlikely(context == NULL)) {
++              context = null_context;
++      }
++
++      if (unlikely(size >= MAX_TALLOC_SIZE)) {
++              return NULL;
++      }
++
++      if (context != NULL) {
++              tc = talloc_alloc_pool(talloc_chunk_from_ptr(context),
++                                     TC_HDR_SIZE+size);
++      }
++
++      if (tc == NULL) {
++              tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size);
++              if (unlikely(tc == NULL)) return NULL;
++              tc->flags = TALLOC_MAGIC;
++              tc->pool  = NULL;
++      }
++
++      tc->size = size;
++      tc->destructor = NULL;
++      tc->child = NULL;
++      tc->name = NULL;
++      tc->refs = NULL;
++
++      if (likely(context)) {
++              struct talloc_chunk *parent = talloc_chunk_from_ptr(context);
++
++              if (parent->child) {
++                      parent->child->parent = NULL;
++                      tc->next = parent->child;
++                      tc->next->prev = tc;
++              } else {
++                      tc->next = NULL;
++              }
++              tc->parent = parent;
++              tc->prev = NULL;
++              parent->child = tc;
++      } else {
++              tc->next = tc->prev = tc->parent = NULL;
++      }
++
++      return TC_PTR_FROM_CHUNK(tc);
++}
++
++/*
++ * Create a talloc pool
++ */
++
++void *talloc_pool(const void *context, size_t size)
++{
++      void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE);
++      struct talloc_chunk *tc;
++
++      if (unlikely(result == NULL)) {
++              return NULL;
++      }
++
++      tc = talloc_chunk_from_ptr(result);
++
++      tc->flags |= TALLOC_FLAG_POOL;
++      tc->pool = (char *)result + TALLOC_POOL_HDR_SIZE;
++
++      *talloc_pool_objectcount(tc) = 1;
++
++#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
++      VALGRIND_MAKE_MEM_NOACCESS(tc->pool, size);
++#endif
++
++      return result;
++}
++
++/*
++  setup a destructor to be called on free of a pointer
++  the destructor should return 0 on success, or -1 on failure.
++  if the destructor fails then the free is failed, and the memory can
++  be continued to be used
++*/
++void _talloc_set_destructor(const void *ptr, int (*destructor)(void *))
++{
++      struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
++      tc->destructor = destructor;
++}
++
++/*
++  increase the reference count on a piece of memory. 
++*/
++int talloc_increase_ref_count(const void *ptr)
++{
++      if (unlikely(!talloc_reference(null_context, ptr))) {
++              return -1;
++      }
++      return 0;
++}
++
++/*
++  helper for talloc_reference()
++
++  this is referenced by a function pointer and should not be inline
++*/
++static int talloc_reference_destructor(struct talloc_reference_handle *handle)
++{
++      struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr);
++      _TLIST_REMOVE(ptr_tc->refs, handle);
++      return 0;
++}
++
++/*
++   more efficient way to add a name to a pointer - the name must point to a 
++   true string constant
++*/
++static inline void _talloc_set_name_const(const void *ptr, const char *name)
++{
++      struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
++      tc->name = name;
++}
++
++/*
++  internal talloc_named_const()
++*/
++static inline void *_talloc_named_const(const void *context, size_t size, const char *name)
++{
++      void *ptr;
++
++      ptr = __talloc(context, size);
++      if (unlikely(ptr == NULL)) {
++              return NULL;
++      }
++
++      _talloc_set_name_const(ptr, name);
++
++      return ptr;
++}
++
++/*
++  make a secondary reference to a pointer, hanging off the given context.
++  the pointer remains valid until both the original caller and this given
++  context are freed.
++  
++  the major use for this is when two different structures need to reference the 
++  same underlying data, and you want to be able to free the two instances separately,
++  and in either order
++*/
++void *_talloc_reference(const void *context, const void *ptr)
++{
++      struct talloc_chunk *tc;
++      struct talloc_reference_handle *handle;
++      if (unlikely(ptr == NULL)) return NULL;
++
++      tc = talloc_chunk_from_ptr(ptr);
++      handle = (struct talloc_reference_handle *)_talloc_named_const(context,
++                                                 sizeof(struct talloc_reference_handle),
++                                                 TALLOC_MAGIC_REFERENCE);
++      if (unlikely(handle == NULL)) return NULL;
++
++      /* note that we hang the destructor off the handle, not the
++         main context as that allows the caller to still setup their
++         own destructor on the context if they want to */
++      talloc_set_destructor(handle, talloc_reference_destructor);
++      handle->ptr = discard_const_p(void, ptr);
++      _TLIST_ADD(tc->refs, handle);
++      return handle->ptr;
++}
++
++
++/* 
++   internal talloc_free call
++*/
++static inline int _talloc_free(void *ptr)
++{
++      struct talloc_chunk *tc;
++
++      if (unlikely(ptr == NULL)) {
++              return -1;
++      }
++
++      tc = talloc_chunk_from_ptr(ptr);
++
++      if (unlikely(tc->refs)) {
++              int is_child;
++              /* check this is a reference from a child or grantchild
++               * back to it's parent or grantparent
++               *
++               * in that case we need to remove the reference and
++               * call another instance of talloc_free() on the current
++               * pointer.
++               */
++              is_child = talloc_is_parent(tc->refs, ptr);
++              _talloc_free(tc->refs);
++              if (is_child) {
++                      return _talloc_free(ptr);
++              }
++              return -1;
++      }
++
++      if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) {
++              /* we have a free loop - stop looping */
++              return 0;
++      }
++
++      if (unlikely(tc->destructor)) {
++              talloc_destructor_t d = tc->destructor;
++              if (d == (talloc_destructor_t)-1) {
++                      return -1;
++              }
++              tc->destructor = (talloc_destructor_t)-1;
++              if (d(ptr) == -1) {
++                      tc->destructor = d;
++                      return -1;
++              }
++              tc->destructor = NULL;
++      }
++
++      if (tc->parent) {
++              _TLIST_REMOVE(tc->parent->child, tc);
++              if (tc->parent->child) {
++                      tc->parent->child->parent = tc->parent;
++              }
++      } else {
++              if (tc->prev) tc->prev->next = tc->next;
++              if (tc->next) tc->next->prev = tc->prev;
++      }
++
++      tc->flags |= TALLOC_FLAG_LOOP;
++
++      while (tc->child) {
++              /* we need to work out who will own an abandoned child
++                 if it cannot be freed. In priority order, the first
++                 choice is owner of any remaining reference to this
++                 pointer, the second choice is our parent, and the
++                 final choice is the null context. */
++              void *child = TC_PTR_FROM_CHUNK(tc->child);
++              const void *new_parent = null_context;
++              if (unlikely(tc->child->refs)) {
++                      struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
++                      if (p) new_parent = TC_PTR_FROM_CHUNK(p);
++              }
++              if (unlikely(_talloc_free(child) == -1)) {
++                      if (new_parent == null_context) {
++                              struct talloc_chunk *p = talloc_parent_chunk(ptr);
++                              if (p) new_parent = TC_PTR_FROM_CHUNK(p);
++                      }
++                      talloc_steal(new_parent, child);
++              }
++      }
++
++      tc->flags |= TALLOC_FLAG_FREE;
++
++      if (tc->flags & (TALLOC_FLAG_POOL|TALLOC_FLAG_POOLMEM)) {
++              struct talloc_chunk *pool;
++              unsigned int *pool_object_count;
++
++              pool = (tc->flags & TALLOC_FLAG_POOL)
++                      ? tc : (struct talloc_chunk *)tc->pool;
++
++              pool_object_count = talloc_pool_objectcount(pool);
++
++              if (*pool_object_count == 0) {
++                      talloc_abort("Pool object count zero!");
++              }
++
++              *pool_object_count -= 1;
++
++              if (*pool_object_count == 0) {
++                      free(pool);
++              }
++      }
++      else {
++              free(tc);
++      }
++      return 0;
++}
++
++/* 
++   move a lump of memory from one talloc context to another return the
++   ptr on success, or NULL if it could not be transferred.
++   passing NULL as ptr will always return NULL with no side effects.
++*/
++void *_talloc_steal(const void *new_ctx, const void *ptr)
++{
++      struct talloc_chunk *tc, *new_tc;
++
++      if (unlikely(!ptr)) {
++              return NULL;
++      }
++
++      if (unlikely(new_ctx == NULL)) {
++              new_ctx = null_context;
++      }
++
++      tc = talloc_chunk_from_ptr(ptr);
++
++      if (unlikely(new_ctx == NULL)) {
++              if (tc->parent) {
++                      _TLIST_REMOVE(tc->parent->child, tc);
++                      if (tc->parent->child) {
++                              tc->parent->child->parent = tc->parent;
++                      }
++              } else {
++                      if (tc->prev) tc->prev->next = tc->next;
++                      if (tc->next) tc->next->prev = tc->prev;
++              }
++              
++              tc->parent = tc->next = tc->prev = NULL;
++              return discard_const_p(void, ptr);
++      }
++
++      new_tc = talloc_chunk_from_ptr(new_ctx);
++
++      if (unlikely(tc == new_tc || tc->parent == new_tc)) {
++              return discard_const_p(void, ptr);
++      }
++
++      if (tc->parent) {
++              _TLIST_REMOVE(tc->parent->child, tc);
++              if (tc->parent->child) {
++                      tc->parent->child->parent = tc->parent;
++              }
++      } else {
++              if (tc->prev) tc->prev->next = tc->next;
++              if (tc->next) tc->next->prev = tc->prev;
++      }
++
++      tc->parent = new_tc;
++      if (new_tc->child) new_tc->child->parent = NULL;
++      _TLIST_ADD(new_tc->child, tc);
++
++      return discard_const_p(void, ptr);
++}
++
++
++
++/*
++  remove a secondary reference to a pointer. This undo's what
++  talloc_reference() has done. The context and pointer arguments
++  must match those given to a talloc_reference()
++*/
++static inline int talloc_unreference(const void *context, const void *ptr)
++{
++      struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
++      struct talloc_reference_handle *h;
++
++      if (unlikely(context == NULL)) {
++              context = null_context;
++      }
++
++      for (h=tc->refs;h;h=h->next) {
++              struct talloc_chunk *p = talloc_parent_chunk(h);
++              if (p == NULL) {
++                      if (context == NULL) break;
++              } else if (TC_PTR_FROM_CHUNK(p) == context) {
++                      break;
++              }
++      }
++      if (h == NULL) {
++              return -1;
++      }
++
++      return _talloc_free(h);
++}
++
++/*
++  remove a specific parent context from a pointer. This is a more
++  controlled varient of talloc_free()
++*/
++int talloc_unlink(const void *context, void *ptr)
++{
++      struct talloc_chunk *tc_p, *new_p;
++      void *new_parent;
++
++      if (ptr == NULL) {
++              return -1;
++      }
++
++      if (context == NULL) {
++              context = null_context;
++      }
++
++      if (talloc_unreference(context, ptr) == 0) {
++              return 0;
++      }
++
++      if (context == NULL) {
++              if (talloc_parent_chunk(ptr) != NULL) {
++                      return -1;
++              }
++      } else {
++              if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) {
++                      return -1;
++              }
++      }
++      
++      tc_p = talloc_chunk_from_ptr(ptr);
++
++      if (tc_p->refs == NULL) {
++              return _talloc_free(ptr);
++      }
++
++      new_p = talloc_parent_chunk(tc_p->refs);
++      if (new_p) {
++              new_parent = TC_PTR_FROM_CHUNK(new_p);
++      } else {
++              new_parent = NULL;
++      }
++
++      if (talloc_unreference(new_parent, ptr) != 0) {
++              return -1;
++      }
++
++      talloc_steal(new_parent, ptr);
++
++      return 0;
++}
++
++/*
++  add a name to an existing pointer - va_list version
++*/
++static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0);
++
++static inline const char *talloc_set_name_v(const void *ptr, const char *fmt, va_list ap)
++{
++      struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
++      tc->name = talloc_vasprintf(ptr, fmt, ap);
++      if (likely(tc->name)) {
++              _talloc_set_name_const(tc->name, ".name");
++      }
++      return tc->name;
++}
++
++/*
++  add a name to an existing pointer
++*/
++const char *talloc_set_name(const void *ptr, const char *fmt, ...)
++{
++      const char *name;
++      va_list ap;
++      va_start(ap, fmt);
++      name = talloc_set_name_v(ptr, fmt, ap);
++      va_end(ap);
++      return name;
++}
++
++
++/*
++  create a named talloc pointer. Any talloc pointer can be named, and
++  talloc_named() operates just like talloc() except that it allows you
++  to name the pointer.
++*/
++void *talloc_named(const void *context, size_t size, const char *fmt, ...)
++{
++      va_list ap;
++      void *ptr;
++      const char *name;
++
++      ptr = __talloc(context, size);
++      if (unlikely(ptr == NULL)) return NULL;
++
++      va_start(ap, fmt);
++      name = talloc_set_name_v(ptr, fmt, ap);
++      va_end(ap);
++
++      if (unlikely(name == NULL)) {
++              _talloc_free(ptr);
++              return NULL;
++      }
++
++      return ptr;
++}
++
++/*
++  return the name of a talloc ptr, or "UNNAMED"
++*/
++const char *talloc_get_name(const void *ptr)
++{
++      struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
++      if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) {
++              return ".reference";
++      }
++      if (likely(tc->name)) {
++              return tc->name;
++      }
++      return "UNNAMED";
++}
++
++
++/*
++  check if a pointer has the given name. If it does, return the pointer,
++  otherwise return NULL
++*/
++void *talloc_check_name(const void *ptr, const char *name)
++{
++      const char *pname;
++      if (unlikely(ptr == NULL)) return NULL;
++      pname = talloc_get_name(ptr);
++      if (likely(pname == name || strcmp(pname, name) == 0)) {
++              return discard_const_p(void, ptr);
++      }
++      return NULL;
++}
++
++static void talloc_abort_type_missmatch(const char *location,
++                                      const char *name,
++                                      const char *expected)
++{
++      const char *reason;
++
++      reason = talloc_asprintf(NULL,
++                               "%s: Type mismatch: name[%s] expected[%s]",
++                               location,
++                               name?name:"NULL",
++                               expected);
++      if (!reason) {
++              reason = "Type mismatch";
++      }
++
++      talloc_abort(reason);
++}
++
++void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
++{
++      const char *pname;
++
++      if (unlikely(ptr == NULL)) {
++              talloc_abort_type_missmatch(location, NULL, name);
++              return NULL;
++      }
++
++      pname = talloc_get_name(ptr);
++      if (likely(pname == name || strcmp(pname, name) == 0)) {
++              return discard_const_p(void, ptr);
++      }
++
++      talloc_abort_type_missmatch(location, pname, name);
++      return NULL;
++}
++
++/*
++  this is for compatibility with older versions of talloc
++*/
++void *talloc_init(const char *fmt, ...)
++{
++      va_list ap;
++      void *ptr;
++      const char *name;
++
++      /*
++       * samba3 expects talloc_report_depth_cb(NULL, ...)
++       * reports all talloc'ed memory, so we need to enable
++       * null_tracking
++       */
++      talloc_enable_null_tracking();
++
++      ptr = __talloc(NULL, 0);
++      if (unlikely(ptr == NULL)) return NULL;
++
++      va_start(ap, fmt);
++      name = talloc_set_name_v(ptr, fmt, ap);
++      va_end(ap);
++
++      if (unlikely(name == NULL)) {
++              _talloc_free(ptr);
++              return NULL;
++      }
++
++      return ptr;
++}
++
++/*
++  this is a replacement for the Samba3 talloc_destroy_pool functionality. It
++  should probably not be used in new code. It's in here to keep the talloc
++  code consistent across Samba 3 and 4.
++*/
++void talloc_free_children(void *ptr)
++{
++      struct talloc_chunk *tc;
++
++      if (unlikely(ptr == NULL)) {
++              return;
++      }
++
++      tc = talloc_chunk_from_ptr(ptr);
++
++      while (tc->child) {
++              /* we need to work out who will own an abandoned child
++                 if it cannot be freed. In priority order, the first
++                 choice is owner of any remaining reference to this
++                 pointer, the second choice is our parent, and the
++                 final choice is the null context. */
++              void *child = TC_PTR_FROM_CHUNK(tc->child);
++              const void *new_parent = null_context;
++              if (unlikely(tc->child->refs)) {
++                      struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
++                      if (p) new_parent = TC_PTR_FROM_CHUNK(p);
++              }
++              if (unlikely(_talloc_free(child) == -1)) {
++                      if (new_parent == null_context) {
++                              struct talloc_chunk *p = talloc_parent_chunk(ptr);
++                              if (p) new_parent = TC_PTR_FROM_CHUNK(p);
++                      }
++                      talloc_steal(new_parent, child);
++              }
++      }
++
++      if ((tc->flags & TALLOC_FLAG_POOL)
++          && (*talloc_pool_objectcount(tc) == 1)) {
++              tc->pool = ((char *)tc + TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE);
++#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS)
++              VALGRIND_MAKE_MEM_NOACCESS(
++                      tc->pool, tc->size - TALLOC_POOL_HDR_SIZE);
++#endif
++      }
++}
++
++/* 
++   Allocate a bit of memory as a child of an existing pointer
++*/
++void *_talloc(const void *context, size_t size)
++{
++      return __talloc(context, size);
++}
++
++/*
++  externally callable talloc_set_name_const()
++*/
++void talloc_set_name_const(const void *ptr, const char *name)
++{
++      _talloc_set_name_const(ptr, name);
++}
++
++/*
++  create a named talloc pointer. Any talloc pointer can be named, and
++  talloc_named() operates just like talloc() except that it allows you
++  to name the pointer.
++*/
++void *talloc_named_const(const void *context, size_t size, const char *name)
++{
++      return _talloc_named_const(context, size, name);
++}
++
++/* 
++   free a talloc pointer. This also frees all child pointers of this 
++   pointer recursively
++
++   return 0 if the memory is actually freed, otherwise -1. The memory
++   will not be freed if the ref_count is > 1 or the destructor (if
++   any) returns non-zero
++*/
++int talloc_free(void *ptr)
++{
++      return _talloc_free(ptr);
++}
++
++
++
++/*
++  A talloc version of realloc. The context argument is only used if
++  ptr is NULL
++*/
++void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name)
++{
++      struct talloc_chunk *tc;
++      void *new_ptr;
++      bool malloced = false;
++
++      /* size zero is equivalent to free() */
++      if (unlikely(size == 0)) {
++              _talloc_free(ptr);
++              return NULL;
++      }
++
++      if (unlikely(size >= MAX_TALLOC_SIZE)) {
++              return NULL;
++      }
++
++      /* realloc(NULL) is equivalent to malloc() */
++      if (ptr == NULL) {
++              return _talloc_named_const(context, size, name);
++      }
++
++      tc = talloc_chunk_from_ptr(ptr);
++
++      /* don't allow realloc on referenced pointers */
++      if (unlikely(tc->refs)) {
++              return NULL;
++      }
++
++      /* don't let anybody try to realloc a talloc_pool */
++      if (unlikely(tc->flags & TALLOC_FLAG_POOL)) {
++              return NULL;
++      }
++
++      /* don't shrink if we have less than 1k to gain */
++      if ((size < tc->size) && ((tc->size - size) < 1024)) {
++              tc->size = size;
++              return ptr;
++      }
++
++      /* by resetting magic we catch users of the old memory */
++      tc->flags |= TALLOC_FLAG_FREE;
++
++#if ALWAYS_REALLOC
++      new_ptr = malloc(size + TC_HDR_SIZE);
++      if (new_ptr) {
++              memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
++              free(tc);
++      }
++#else
++      if (tc->flags & TALLOC_FLAG_POOLMEM) {
++
++              new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE);
++              *talloc_pool_objectcount((struct talloc_chunk *)
++                                       (tc->pool)) -= 1;
++
++              if (new_ptr == NULL) {
++                      new_ptr = malloc(TC_HDR_SIZE+size);
++                      malloced = true;
++              }
++
++              if (new_ptr) {
++                      memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE);
++              }
++      }
++      else {
++              new_ptr = realloc(tc, size + TC_HDR_SIZE);
++      }
++#endif
++      if (unlikely(!new_ptr)) {       
++              tc->flags &= ~TALLOC_FLAG_FREE; 
++              return NULL; 
++      }
++
++      tc = (struct talloc_chunk *)new_ptr;
++      tc->flags &= ~TALLOC_FLAG_FREE;
++      if (malloced) {
++              tc->flags &= ~TALLOC_FLAG_POOLMEM;
++      }
++      if (tc->parent) {
++              tc->parent->child = tc;
++      }
++      if (tc->child) {
++              tc->child->parent = tc;
++      }
++
++      if (tc->prev) {
++              tc->prev->next = tc;
++      }
++      if (tc->next) {
++              tc->next->prev = tc;
++      }
++
++      tc->size = size;
++      _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
++
++      return TC_PTR_FROM_CHUNK(tc);
++}
++
++/*
++  a wrapper around talloc_steal() for situations where you are moving a pointer
++  between two structures, and want the old pointer to be set to NULL
++*/
++void *_talloc_move(const void *new_ctx, const void *_pptr)
++{
++      const void **pptr = discard_const_p(const void *,_pptr);
++      void *ret = _talloc_steal(new_ctx, *pptr);
++      (*pptr) = NULL;
++      return ret;
++}
++
++/*
++  return the total size of a talloc pool (subtree)
++*/
++size_t talloc_total_size(const void *ptr)
++{
++      size_t total = 0;
++      struct talloc_chunk *c, *tc;
++
++      if (ptr == NULL) {
++              ptr = null_context;
++      }
++      if (ptr == NULL) {
++              return 0;
++      }
++
++      tc = talloc_chunk_from_ptr(ptr);
++
++      if (tc->flags & TALLOC_FLAG_LOOP) {
++              return 0;
++      }
++
++      tc->flags |= TALLOC_FLAG_LOOP;
++
++      total = tc->size;
++      for (c=tc->child;c;c=c->next) {
++              total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
++      }
++
++      tc->flags &= ~TALLOC_FLAG_LOOP;
++
++      return total;
++}
++
++/*
++  return the total number of blocks in a talloc pool (subtree)
++*/
++size_t talloc_total_blocks(const void *ptr)
++{
++      size_t total = 0;
++      struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
++
++      if (tc->flags & TALLOC_FLAG_LOOP) {
++              return 0;
++      }
++
++      tc->flags |= TALLOC_FLAG_LOOP;
++
++      total++;
++      for (c=tc->child;c;c=c->next) {
++              total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
++      }
++
++      tc->flags &= ~TALLOC_FLAG_LOOP;
++
++      return total;
++}
++
++/*
++  return the number of external references to a pointer
++*/
++size_t talloc_reference_count(const void *ptr)
++{
++      struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
++      struct talloc_reference_handle *h;
++      size_t ret = 0;
++
++      for (h=tc->refs;h;h=h->next) {
++              ret++;
++      }
++      return ret;
++}
++
++/*
++  report on memory usage by all children of a pointer, giving a full tree view
++*/
++void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
++                          void (*callback)(const void *ptr,
++                                           int depth, int max_depth,
++                                           int is_ref,
++                                           void *private_data),
++                          void *private_data)
++{
++      struct talloc_chunk *c, *tc;
++
++      if (ptr == NULL) {
++              ptr = null_context;
++      }
++      if (ptr == NULL) return;
++
++      tc = talloc_chunk_from_ptr(ptr);
++
++      if (tc->flags & TALLOC_FLAG_LOOP) {
++              return;
++      }
++
++      callback(ptr, depth, max_depth, 0, private_data);
++
++      if (max_depth >= 0 && depth >= max_depth) {
++              return;
++      }
++
++      tc->flags |= TALLOC_FLAG_LOOP;
++      for (c=tc->child;c;c=c->next) {
++              if (c->name == TALLOC_MAGIC_REFERENCE) {
++                      struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c);
++                      callback(h->ptr, depth + 1, max_depth, 1, private_data);
++              } else {
++                      talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data);
++              }
++      }
++      tc->flags &= ~TALLOC_FLAG_LOOP;
++}
++
++static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f)
++{
++      const char *name = talloc_get_name(ptr);
++      FILE *f = (FILE *)_f;
++
++      if (is_ref) {
++              fprintf(f, "%*sreference to: %s\n", depth*4, "", name);
++              return;
++      }
++
++      if (depth == 0) {
++              fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", 
++                      (max_depth < 0 ? "full " :""), name,
++                      (unsigned long)talloc_total_size(ptr),
++                      (unsigned long)talloc_total_blocks(ptr));
++              return;
++      }
++
++      fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", 
++              depth*4, "",
++              name,
++              (unsigned long)talloc_total_size(ptr),
++              (unsigned long)talloc_total_blocks(ptr),
++              (int)talloc_reference_count(ptr), ptr);
++
++#if 0
++      fprintf(f, "content: ");
++      if (talloc_total_size(ptr)) {
++              int tot = talloc_total_size(ptr);
++              int i;
++
++              for (i = 0; i < tot; i++) {
++                      if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) {
++                              fprintf(f, "%c", ((char *)ptr)[i]);
++                      } else {
++                              fprintf(f, "~%02x", ((char *)ptr)[i]);
++                      }
++              }
++      }
++      fprintf(f, "\n");
++#endif
++}
++
++/*
++  report on memory usage by all children of a pointer, giving a full tree view
++*/
++void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f)
++{
++      talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f);
++      fflush(f);
++}
++
++/*
++  report on memory usage by all children of a pointer, giving a full tree view
++*/
++void talloc_report_full(const void *ptr, FILE *f)
++{
++      talloc_report_depth_file(ptr, 0, -1, f);
++}
++
++/*
++  report on memory usage by all children of a pointer
++*/
++void talloc_report(const void *ptr, FILE *f)
++{
++      talloc_report_depth_file(ptr, 0, 1, f);
++}
++
++/*
++  report on any memory hanging off the null context
++*/
++static void talloc_report_null(void)
++{
++      if (talloc_total_size(null_context) != 0) {
++              talloc_report(null_context, stderr);
++      }
++}
++
++/*
++  report on any memory hanging off the null context
++*/
++static void talloc_report_null_full(void)
++{
++      if (talloc_total_size(null_context) != 0) {
++              talloc_report_full(null_context, stderr);
++      }
++}
++
++/*
++  enable tracking of the NULL context
++*/
++void talloc_enable_null_tracking(void)
++{
++      if (null_context == NULL) {
++              null_context = _talloc_named_const(NULL, 0, "null_context");
++      }
++}
++
++/*
++  disable tracking of the NULL context
++*/
++void talloc_disable_null_tracking(void)
++{
++      _talloc_free(null_context);
++      null_context = NULL;
++}
++
++/*
++  enable leak reporting on exit
++*/
++void talloc_enable_leak_report(void)
++{
++      talloc_enable_null_tracking();
++      atexit(talloc_report_null);
++}
++
++/*
++  enable full leak reporting on exit
++*/
++void talloc_enable_leak_report_full(void)
++{
++      talloc_enable_null_tracking();
++      atexit(talloc_report_null_full);
++}
++
++/* 
++   talloc and zero memory. 
++*/
++void *_talloc_zero(const void *ctx, size_t size, const char *name)
++{
++      void *p = _talloc_named_const(ctx, size, name);
++
++      if (p) {
++              memset(p, '\0', size);
++      }
++
++      return p;
++}
++
++/*
++  memdup with a talloc. 
++*/
++void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name)
++{
++      void *newp = _talloc_named_const(t, size, name);
++
++      if (likely(newp)) {
++              memcpy(newp, p, size);
++      }
++
++      return newp;
++}
++
++static inline char *__talloc_strlendup(const void *t, const char *p, size_t len)
++{
++      char *ret;
++
++      ret = (char *)__talloc(t, len + 1);
++      if (unlikely(!ret)) return NULL;
++
++      memcpy(ret, p, len);
++      ret[len] = 0;
++
++      _talloc_set_name_const(ret, ret);
++      return ret;
++}
++
++/*
++  strdup with a talloc
++*/
++char *talloc_strdup(const void *t, const char *p)
++{
++      if (unlikely(!p)) return NULL;
++      return __talloc_strlendup(t, p, strlen(p));
++}
++
++/*
++  strndup with a talloc
++*/
++char *talloc_strndup(const void *t, const char *p, size_t n)
++{
++      if (unlikely(!p)) return NULL;
++      return __talloc_strlendup(t, p, strnlen(p, n));
++}
++
++static inline char *__talloc_strlendup_append(char *s, size_t slen,
++                                            const char *a, size_t alen)
++{
++      char *ret;
++
++      ret = talloc_realloc(NULL, s, char, slen + alen + 1);
++      if (unlikely(!ret)) return NULL;
++
++      /* append the string and the trailing \0 */
++      memcpy(&ret[slen], a, alen);
++      ret[slen+alen] = 0;
++
++      _talloc_set_name_const(ret, ret);
++      return ret;
++}
++
++/*
++ * Appends at the end of the string.
++ */
++char *talloc_strdup_append(char *s, const char *a)
++{
++      if (unlikely(!s)) {
++              return talloc_strdup(NULL, a);
++      }
++
++      if (unlikely(!a)) {
++              return s;
++      }
++
++      return __talloc_strlendup_append(s, strlen(s), a, strlen(a));
++}
++
++/*
++ * Appends at the end of the talloc'ed buffer,
++ * not the end of the string.
++ */
++char *talloc_strdup_append_buffer(char *s, const char *a)
++{
++      size_t slen;
++
++      if (unlikely(!s)) {
++              return talloc_strdup(NULL, a);
++      }
++
++      if (unlikely(!a)) {
++              return s;
++      }
++
++      slen = talloc_get_size(s);
++      if (likely(slen > 0)) {
++              slen--;
++      }
++
++      return __talloc_strlendup_append(s, slen, a, strlen(a));
++}
++
++/*
++ * Appends at the end of the string.
++ */
++char *talloc_strndup_append(char *s, const char *a, size_t n)
++{
++      if (unlikely(!s)) {
++              return talloc_strdup(NULL, a);
++      }
++
++      if (unlikely(!a)) {
++              return s;
++      }
++
++      return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n));
++}
++
++/*
++ * Appends at the end of the talloc'ed buffer,
++ * not the end of the string.
++ */
++char *talloc_strndup_append_buffer(char *s, const char *a, size_t n)
++{
++      size_t slen;
++
++      if (unlikely(!s)) {
++              return talloc_strdup(NULL, a);
++      }
++
++      if (unlikely(!a)) {
++              return s;
++      }
++
++      slen = talloc_get_size(s);
++      if (likely(slen > 0)) {
++              slen--;
++      }
++
++      return __talloc_strlendup_append(s, slen, a, strnlen(a, n));
++}
++
++#ifndef HAVE_VA_COPY
++#ifdef HAVE___VA_COPY
++#define va_copy(dest, src) __va_copy(dest, src)
++#else
++#define va_copy(dest, src) (dest) = (src)
++#endif
++#endif
++
++char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
++{
++      int len;
++      char *ret;
++      va_list ap2;
++      char c;
++
++      /* this call looks strange, but it makes it work on older solaris boxes */
++      va_copy(ap2, ap);
++      len = vsnprintf(&c, 1, fmt, ap2);
++      va_end(ap2);
++      if (unlikely(len < 0)) {
++              return NULL;
++      }
++
++      ret = (char *)__talloc(t, len+1);
++      if (unlikely(!ret)) return NULL;
++
++      va_copy(ap2, ap);
++      vsnprintf(ret, len+1, fmt, ap2);
++      va_end(ap2);
++
++      _talloc_set_name_const(ret, ret);
++      return ret;
++}
++
++
++/*
++  Perform string formatting, and return a pointer to newly allocated
++  memory holding the result, inside a memory pool.
++ */
++char *talloc_asprintf(const void *t, const char *fmt, ...)
++{
++      va_list ap;
++      char *ret;
++
++      va_start(ap, fmt);
++      ret = talloc_vasprintf(t, fmt, ap);
++      va_end(ap);
++      return ret;
++}
++
++static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
++                                               const char *fmt, va_list ap)
++                                               PRINTF_ATTRIBUTE(3,0);
++
++static inline char *__talloc_vaslenprintf_append(char *s, size_t slen,
++                                               const char *fmt, va_list ap)
++{
++      ssize_t alen;
++      va_list ap2;
++      char c;
++
++      va_copy(ap2, ap);
++      alen = vsnprintf(&c, 1, fmt, ap2);
++      va_end(ap2);
++
++      if (alen <= 0) {
++              /* Either the vsnprintf failed or the format resulted in
++               * no characters being formatted. In the former case, we
++               * ought to return NULL, in the latter we ought to return
++               * the original string. Most current callers of this
++               * function expect it to never return NULL.
++               */
++              return s;
++      }
++
++      s = talloc_realloc(NULL, s, char, slen + alen + 1);
++      if (!s) return NULL;
++
++      va_copy(ap2, ap);
++      vsnprintf(s + slen, alen + 1, fmt, ap2);
++      va_end(ap2);
++
++      _talloc_set_name_const(s, s);
++      return s;
++}
++
++/**
++ * Realloc @p s to append the formatted result of @p fmt and @p ap,
++ * and return @p s, which may have moved.  Good for gradually
++ * accumulating output into a string buffer. Appends at the end
++ * of the string.
++ **/
++char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
++{
++      if (unlikely(!s)) {
++              return talloc_vasprintf(NULL, fmt, ap);
++      }
++
++      return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap);
++}
++
++/**
++ * Realloc @p s to append the formatted result of @p fmt and @p ap,
++ * and return @p s, which may have moved. Always appends at the
++ * end of the talloc'ed buffer, not the end of the string.
++ **/
++char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap)
++{
++      size_t slen;
++
++      if (unlikely(!s)) {
++              return talloc_vasprintf(NULL, fmt, ap);
++      }
++
++      slen = talloc_get_size(s);
++      if (likely(slen > 0)) {
++              slen--;
++      }
++
++      return __talloc_vaslenprintf_append(s, slen, fmt, ap);
++}
++
++/*
++  Realloc @p s to append the formatted result of @p fmt and return @p
++  s, which may have moved.  Good for gradually accumulating output
++  into a string buffer.
++ */
++char *talloc_asprintf_append(char *s, const char *fmt, ...)
++{
++      va_list ap;
++
++      va_start(ap, fmt);
++      s = talloc_vasprintf_append(s, fmt, ap);
++      va_end(ap);
++      return s;
++}
++
++/*
++  Realloc @p s to append the formatted result of @p fmt and return @p
++  s, which may have moved.  Good for gradually accumulating output
++  into a buffer.
++ */
++char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...)
++{
++      va_list ap;
++
++      va_start(ap, fmt);
++      s = talloc_vasprintf_append_buffer(s, fmt, ap);
++      va_end(ap);
++      return s;
++}
++
++/*
++  alloc an array, checking for integer overflow in the array size
++*/
++void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name)
++{
++      if (count >= MAX_TALLOC_SIZE/el_size) {
++              return NULL;
++      }
++      return _talloc_named_const(ctx, el_size * count, name);
++}
++
++/*
++  alloc an zero array, checking for integer overflow in the array size
++*/
++void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name)
++{
++      if (count >= MAX_TALLOC_SIZE/el_size) {
++              return NULL;
++      }
++      return _talloc_zero(ctx, el_size * count, name);
++}
++
++/*
++  realloc an array, checking for integer overflow in the array size
++*/
++void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name)
++{
++      if (count >= MAX_TALLOC_SIZE/el_size) {
++              return NULL;
++      }
++      return _talloc_realloc(ctx, ptr, el_size * count, name);
++}
++
++/*
++  a function version of talloc_realloc(), so it can be passed as a function pointer
++  to libraries that want a realloc function (a realloc function encapsulates
++  all the basic capabilities of an allocation library, which is why this is useful)
++*/
++void *talloc_realloc_fn(const void *context, void *ptr, size_t size)
++{
++      return _talloc_realloc(context, ptr, size, NULL);
++}
++
++
++static int talloc_autofree_destructor(void *ptr)
++{
++      autofree_context = NULL;
++      return 0;
++}
++
++static void talloc_autofree(void)
++{
++      _talloc_free(autofree_context);
++}
++
++/*
++  return a context which will be auto-freed on exit
++  this is useful for reducing the noise in leak reports
++*/
++void *talloc_autofree_context(void)
++{
++      if (autofree_context == NULL) {
++              autofree_context = _talloc_named_const(NULL, 0, "autofree_context");
++              talloc_set_destructor(autofree_context, talloc_autofree_destructor);
++              atexit(talloc_autofree);
++      }
++      return autofree_context;
++}
++
++size_t talloc_get_size(const void *context)
++{
++      struct talloc_chunk *tc;
++
++      if (context == NULL)
++              return 0;
++
++      tc = talloc_chunk_from_ptr(context);
++
++      return tc->size;
++}
++
++/*
++  find a parent of this context that has the given name, if any
++*/
++void *talloc_find_parent_byname(const void *context, const char *name)
++{
++      struct talloc_chunk *tc;
++
++      if (context == NULL) {
++              return NULL;
++      }
++
++      tc = talloc_chunk_from_ptr(context);
++      while (tc) {
++              if (tc->name && strcmp(tc->name, name) == 0) {
++                      return TC_PTR_FROM_CHUNK(tc);
++              }
++              while (tc && tc->prev) tc = tc->prev;
++              if (tc) {
++                      tc = tc->parent;
++              }
++      }
++      return NULL;
++}
++
++/*
++  show the parentage of a context
++*/
++void talloc_show_parents(const void *context, FILE *file)
++{
++      struct talloc_chunk *tc;
++
++      if (context == NULL) {
++              fprintf(file, "talloc no parents for NULL\n");
++              return;
++      }
++
++      tc = talloc_chunk_from_ptr(context);
++      fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
++      while (tc) {
++              fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
++              while (tc && tc->prev) tc = tc->prev;
++              if (tc) {
++                      tc = tc->parent;
++              }
++      }
++      fflush(file);
++}
++
++/*
++  return 1 if ptr is a parent of context
++*/
++int talloc_is_parent(const void *context, const void *ptr)
++{
++      struct talloc_chunk *tc;
++
++      if (context == NULL) {
++              return 0;
++      }
++
++      tc = talloc_chunk_from_ptr(context);
++      while (tc) {
++              if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1;
++              while (tc && tc->prev) tc = tc->prev;
++              if (tc) {
++                      tc = tc->parent;
++              }
++      }
++      return 0;
++}
index 0000000,0000000..37d7d16
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,185 @@@
++/*
++ * (C) 2008,2009 by Holger Hans Peter Freyther <zecke@selfish.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <assert.h>
++#include <string.h>
++#include <osmocore/timer.h>
++
++static LLIST_HEAD(timer_list);
++static struct timeval s_nearest_time;
++static struct timeval s_select_time;
++
++#define MICRO_SECONDS  1000000LL
++
++#define TIME_SMALLER(left, right) \
++        (left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec)
++
++void bsc_add_timer(struct timer_list *timer)
++{
++      struct timer_list *list_timer;
++
++      /* TODO: Optimize and remember the closest item... */
++      timer->active = 1;
++
++      /* this might be called from within update_timers */
++      llist_for_each_entry(list_timer, &timer_list, entry)
++              if (timer == list_timer)
++                      return;
++
++      timer->in_list = 1;
++      llist_add(&timer->entry, &timer_list);
++}
++
++void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds)
++{
++      struct timeval current_time;
++
++      gettimeofday(&current_time, NULL);
++      unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
++      currentTime += seconds * MICRO_SECONDS + microseconds;
++      timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
++      timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
++      bsc_add_timer(timer);
++}
++
++void bsc_del_timer(struct timer_list *timer)
++{
++      if (timer->in_list) {
++              timer->active = 0;
++              timer->in_list = 0;
++              llist_del(&timer->entry);
++      }
++}
++
++int bsc_timer_pending(struct timer_list *timer)
++{
++      return timer->active;
++}
++
++/*
++ * if we have a nearest time return the delta between the current
++ * time and the time of the nearest timer.
++ * If the nearest timer timed out return NULL and then we will
++ * dispatch everything after the select
++ */
++struct timeval *bsc_nearest_timer()
++{
++      struct timeval current_time;
++
++      if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
++              return NULL;
++
++      if (gettimeofday(&current_time, NULL) == -1)
++              return NULL;
++
++      unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
++      unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
++
++      if (nearestTime < currentTime) {
++              s_select_time.tv_sec = 0;
++              s_select_time.tv_usec = 0;
++      } else {
++              s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
++              s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
++      }
++
++      return &s_select_time;
++}
++
++/*
++ * Find the nearest time and update s_nearest_time
++ */
++void bsc_prepare_timers()
++{
++      struct timer_list *timer, *nearest_timer = NULL;
++      llist_for_each_entry(timer, &timer_list, entry) {
++              if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) {
++                      nearest_timer = timer;
++              }
++      }
++
++      if (nearest_timer) {
++              s_nearest_time = nearest_timer->timeout;
++      } else {
++              memset(&s_nearest_time, 0, sizeof(struct timeval));
++      }
++}
++
++/*
++ * fire all timers... and remove them
++ */
++int bsc_update_timers()
++{
++      struct timeval current_time;
++      struct timer_list *timer, *tmp;
++      int work = 0;
++
++      gettimeofday(&current_time, NULL);
++
++      /*
++       * The callbacks might mess with our list and in this case
++       * even llist_for_each_entry_safe is not safe to use. To allow
++       * del_timer, add_timer, schedule_timer to be called from within
++       * the callback we jump through some loops.
++       *
++       * First we set the handled flag of each active timer to zero,
++       * then we iterate over the list and execute the callbacks. As the
++       * list might have been changed (specially the next) from within
++       * the callback we have to start over again. Once every callback
++       * is dispatched we will remove the non-active from the list.
++       *
++       * TODO: If this is a performance issue we can poison a global
++       * variable in add_timer and del_timer and only then restart.
++       */
++      llist_for_each_entry(timer, &timer_list, entry) {
++              timer->handled = 0;
++      }
++
++restart:
++      llist_for_each_entry(timer, &timer_list, entry) {
++              if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) {
++                      timer->handled = 1;
++                      timer->active = 0;
++                      (*timer->cb)(timer->data);
++                      work = 1;
++                      goto restart;
++              }
++      }
++
++      llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
++              timer->handled = 0;
++              if (!timer->active) {
++                      bsc_del_timer(timer);
++              }
++      }
++
++      return work;
++}
++
++int bsc_timer_check(void)
++{
++      struct timer_list *timer;
++      int i = 0;
++
++      llist_for_each_entry(timer, &timer_list, entry) {
++              i++;
++      }
++      return i;
++}
index 0000000,0000000..407e57a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,171 @@@
++#include <stdio.h>
++#include <stdint.h>
++#include <osmocore/utils.h>
++#include <osmocore/tlv.h>
++
++struct tlv_definition tvlv_att_def;
++
++int tlv_dump(struct tlv_parsed *dec)
++{
++      int i;
++
++      for (i = 0; i <= 0xff; i++) {
++              if (!dec->lv[i].val)
++                      continue;
++              printf("T=%02x L=%d\n", i, dec->lv[i].len);
++      }
++      return 0;
++}
++
++/* o_tag:  output: tag found
++ * o_len:  output: length of the data
++ * o_val:  output: pointer to the data
++ * def:     input: a structure defining the valid TLV tags / configurations
++ * buf:     input: the input data buffer to be parsed
++ * buf_len: input: the length of the input data buffer
++ *
++ * Also, returns the number of bytes consumed by the TLV entry
++ */
++int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val,
++                const struct tlv_definition *def,
++                const uint8_t *buf, int buf_len)
++{
++      uint8_t tag;
++      int len;
++
++      tag = *buf;
++      *o_tag = tag;
++
++      /* FIXME: use tables for knwon IEI */
++      switch (def->def[tag].type) {
++      case TLV_TYPE_T:
++              /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */
++              *o_val = buf;
++              *o_len = 0;
++              len = 1;
++              break;
++      case TLV_TYPE_TV:
++              *o_val = buf+1;
++              *o_len = 1;
++              len = 2;
++              break;
++      case TLV_TYPE_FIXED:
++              *o_val = buf+1;
++              *o_len = def->def[tag].fixed_len;
++              len = def->def[tag].fixed_len + 1;
++              break;
++      case TLV_TYPE_TLV:
++              /* GSM TS 04.07 11.2.4: Type 4 TLV */
++              if (buf + 1 > buf + buf_len)
++                      return -1;
++              *o_val = buf+2;
++              *o_len = *(buf+1);
++              len = *o_len + 2;
++              if (len > buf_len)
++                      return -2;
++              break;
++      case TLV_TYPE_TvLV:
++              if (*(buf+1) & 0x80) {
++                      /* like TLV, but without highest bit of len */
++                      if (buf + 1 > buf + buf_len)
++                              return -1;
++                      *o_val = buf+2;
++                      *o_len = *(buf+1) & 0x7f;
++                      len = *o_len + 2;
++                      if (len > buf_len)
++                              return -2;
++                      break;
++              }
++              /* like TL16V, fallthrough */
++      case TLV_TYPE_TL16V:
++              if (2 > buf_len)
++                      return -1;
++              *o_val = buf+3;
++              *o_len = *(buf+1) << 8 | *(buf+2);
++              len = *o_len + 3;
++              if (len > buf_len)
++                      return -2;
++              break;
++      default:
++              return -3;
++      }
++
++      return len;
++}
++
++/* dec:    output: a caller-allocated pointer to a struct tlv_parsed,
++ * def:     input: a structure defining the valid TLV tags / configurations
++ * buf:     input: the input data buffer to be parsed
++ * buf_len: input: the length of the input data buffer
++ * lv_tag:  input: an initial LV tag at the start of the buffer
++ * lv_tag2: input: a second initial LV tag following lv_tag 
++ */
++int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
++            const uint8_t *buf, int buf_len, uint8_t lv_tag,
++            uint8_t lv_tag2)
++{
++      int ofs = 0, num_parsed = 0;
++      uint16_t len;
++
++      memset(dec, 0, sizeof(*dec));
++
++      if (lv_tag) {
++              if (ofs > buf_len)
++                      return -1;
++              dec->lv[lv_tag].val = &buf[ofs+1];
++              dec->lv[lv_tag].len = buf[ofs];
++              len = dec->lv[lv_tag].len + 1;
++              if (ofs + len > buf_len)
++                      return -2;
++              num_parsed++;
++              ofs += len;
++      }
++      if (lv_tag2) {
++              if (ofs > buf_len)
++                      return -1;
++              dec->lv[lv_tag2].val = &buf[ofs+1];
++              dec->lv[lv_tag2].len = buf[ofs];
++              len = dec->lv[lv_tag2].len + 1;
++              if (ofs + len > buf_len)
++                      return -2;
++              num_parsed++;
++              ofs += len;
++      }
++
++      while (ofs < buf_len) {
++              int rv;
++              uint8_t tag;
++              const uint8_t *val;
++
++              rv = tlv_parse_one(&tag, &len, &val, def,
++                                 &buf[ofs], buf_len-ofs);
++              if (rv < 0)
++                      return rv;
++              dec->lv[tag].val = val;
++              dec->lv[tag].len = len;
++              ofs += rv;
++              num_parsed++;
++      }
++      //tlv_dump(dec);
++      return num_parsed;
++}
++
++/* take a master (src) tlvdev and fill up all empty slots in 'dst' */
++void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(dst->def); i++) {
++              if (src->def[i].type == TLV_TYPE_NONE)
++                      continue;
++              if (dst->def[i].type == TLV_TYPE_NONE)
++                      dst->def[i] = src->def[i];
++      }
++}
++
++static __attribute__((constructor)) void on_dso_load_tlv(void)
++{
++      int i;
++      for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++)
++              tvlv_att_def.def[i].type = TLV_TYPE_TvLV;
++}
index 0000000,0000000..56e8b6f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++SUBDIRS = timer sms
index 0000000,0000000..a8f1ff6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++INCLUDES = $(all_includes) -I$(top_srcdir)/include
++noinst_PROGRAMS = sms_test
++
++sms_test_SOURCES = sms_test.c
++sms_test_LDADD = $(top_builddir)/src/libosmocore.la
index 0000000,0000000..f5183d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,47 @@@
++/*
++ * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <osmocore/msgb.h>
++#include <osmocore/gsm_utils.h>
++
++int main(int argc, char** argv)
++{
++      printf("SMS testing\n");
++      struct msgb *msg;
++      uint8_t *sms;
++      uint8_t i;
++
++        /* test 7-bit coding/decoding */
++      const char *input = "test text";
++      uint8_t length;
++      uint8_t coded[256];
++      char result[256];
++
++      length = gsm_7bit_encode(coded, input);
++      gsm_7bit_decode(result, coded, length);
++      if (strcmp(result, input) != 0) {
++              printf("7 Bit coding failed... life sucks\n");
++              printf("Wanted: '%s' got '%s'\n", input, result);
++      }
++}
index 0000000,0000000..d3decf5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++INCLUDES = $(all_includes) -I$(top_srcdir)/include
++noinst_PROGRAMS = timer_test
++
++timer_test_SOURCES = timer_test.c
++timer_test_LDADD = $(top_builddir)/src/libosmocore.la
++
index 0000000,0000000..f1b4ad7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,76 @@@
++/*
++ * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ */
++
++#include <stdio.h>
++
++#include <osmocore/timer.h>
++#include <osmocore/select.h>
++
++#include "../config.h"
++
++static void timer_fired(unsigned long data);
++
++static struct timer_list timer_one = {
++    .cb = timer_fired,
++    .data = (void*)1,
++};
++
++static struct timer_list timer_two = {
++    .cb = timer_fired,
++    .data = (void*)2,
++};
++
++static struct timer_list timer_three = {
++    .cb = timer_fired,
++    .data = (void*)3,
++};
++
++static void timer_fired(unsigned long data)
++{
++    printf("Fired timer: %lu\n", data);
++
++    if (data == 1) {
++        bsc_schedule_timer(&timer_one, 3, 0);
++        bsc_del_timer(&timer_two);
++    } else if (data == 2) {
++        printf("Should not be fired... bug in del_timer\n");
++    } else if (data == 3) {
++        printf("Timer fired not registering again\n");
++    } else  {
++        printf("wtf... wrong data\n");
++    }
++}
++
++int main(int argc, char** argv)
++{
++    printf("Starting... timer\n");
++
++    bsc_schedule_timer(&timer_one, 3, 0);
++    bsc_schedule_timer(&timer_two, 5, 0);
++    bsc_schedule_timer(&timer_three, 4, 0);
++
++#ifdef HAVE_SYS_SELECT_H
++    while (1) {
++        bsc_select_main(0);
++    }
++#else
++    printf("Select not supported on this platform!\n");
++#endif
++}