intial checkin of the libosmocore project
diff --git a/include/osmocore/bitvec.h b/include/osmocore/bitvec.h
new file mode 100644
index 0000000..11cb01e
--- /dev/null
+++ b/include/osmocore/bitvec.h
@@ -0,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 */
diff --git a/include/osmocore/comp128.h b/include/osmocore/comp128.h
new file mode 100644
index 0000000..c37808f
--- /dev/null
+++ b/include/osmocore/comp128.h
@@ -0,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__ */
+
diff --git a/include/osmocore/gsm_utils.h b/include/osmocore/gsm_utils.h
new file mode 100644
index 0000000..57521ac
--- /dev/null
+++ b/include/osmocore/gsm_utils.h
@@ -0,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
diff --git a/include/osmocore/gsmtap.h b/include/osmocore/gsmtap.h
new file mode 100644
index 0000000..81b9cc0
--- /dev/null
+++ b/include/osmocore/gsmtap.h
@@ -0,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 */
diff --git a/include/osmocore/linuxlist.h b/include/osmocore/linuxlist.h
new file mode 100644
index 0000000..fb99c5e
--- /dev/null
+++ b/include/osmocore/linuxlist.h
@@ -0,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
diff --git a/include/osmocore/msgb.h b/include/osmocore/msgb.h
new file mode 100644
index 0000000..131f920
--- /dev/null
+++ b/include/osmocore/msgb.h
@@ -0,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 */
diff --git a/include/osmocore/protocol/gsm_04_08.h b/include/osmocore/protocol/gsm_04_08.h
new file mode 100644
index 0000000..801b9b5
--- /dev/null
+++ b/include/osmocore/protocol/gsm_04_08.h
@@ -0,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 */
diff --git a/include/osmocore/protocol/gsm_04_11.h b/include/osmocore/protocol/gsm_04_11.h
new file mode 100644
index 0000000..c6a2b19
--- /dev/null
+++ b/include/osmocore/protocol/gsm_04_11.h
@@ -0,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 */
diff --git a/include/osmocore/protocol/gsm_04_80.h b/include/osmocore/protocol/gsm_04_80.h
new file mode 100644
index 0000000..fa5c945
--- /dev/null
+++ b/include/osmocore/protocol/gsm_04_80.h
@@ -0,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 */
diff --git a/include/osmocore/protocol/gsm_08_58.h b/include/osmocore/protocol/gsm_08_58.h
new file mode 100644
index 0000000..ca9398f
--- /dev/null
+++ b/include/osmocore/protocol/gsm_08_58.h
@@ -0,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 */
diff --git a/include/osmocore/protocol/gsm_12_21.h b/include/osmocore/protocol/gsm_12_21.h
new file mode 100644
index 0000000..ac6db4b
--- /dev/null
+++ b/include/osmocore/protocol/gsm_12_21.h
@@ -0,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 */
diff --git a/include/osmocore/select.h b/include/osmocore/select.h
new file mode 100644
index 0000000..2d8b3ec
--- /dev/null
+++ b/include/osmocore/select.h
@@ -0,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 */
diff --git a/include/osmocore/signal.h b/include/osmocore/signal.h
new file mode 100644
index 0000000..02d83d2
--- /dev/null
+++ b/include/osmocore/signal.h
@@ -0,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 */
diff --git a/include/osmocore/statistics.h b/include/osmocore/statistics.h
new file mode 100644
index 0000000..1d56054
--- /dev/null
+++ b/include/osmocore/statistics.h
@@ -0,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 */
diff --git a/include/osmocore/talloc.h b/include/osmocore/talloc.h
new file mode 100644
index 0000000..f7f7643
--- /dev/null
+++ b/include/osmocore/talloc.h
@@ -0,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
diff --git a/include/osmocore/timer.h b/include/osmocore/timer.h
new file mode 100644
index 0000000..fee888b
--- /dev/null
+++ b/include/osmocore/timer.h
@@ -0,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
diff --git a/include/osmocore/tlv.h b/include/osmocore/tlv.h
new file mode 100644
index 0000000..14c9910
--- /dev/null
+++ b/include/osmocore/tlv.h
@@ -0,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 */
diff --git a/include/osmocore/utils.h b/include/osmocore/utils.h
new file mode 100644
index 0000000..198f45a
--- /dev/null
+++ b/include/osmocore/utils.h
@@ -0,0 +1,6 @@
+#ifndef OSMOCORE_UTIL_H
+#define OSMOCORE_UTIL_H
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#endif