include: reorganize headers file to include/osmocom/[gsm|core]

This patch moves all GSM-specific definitions to include/osmocom/gsm.
Moreover, the headers in include/osmocore/ have been moved to
include/osmocom/core.

This has been proposed by Harald Welte and Sylvain Munaunt.

Tested with `make distcheck'.

Signed-off-by: Pablo Neira Ayuso <pablo@gnumonks.org>
diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am
index ec548fb..21f4f2d 100644
--- a/include/osmocom/Makefile.am
+++ b/include/osmocom/Makefile.am
@@ -1,5 +1,5 @@
 if ENABLE_VTY
-SUBDIRS = vty codec crypt
+SUBDIRS = vty codec crypt gsm core
 else
-SUBDIRS = codec crypt
+SUBDIRS = codec crypt gsm core
 endif
diff --git a/include/osmocom/core/Makefile.am b/include/osmocom/core/Makefile.am
new file mode 100644
index 0000000..6109f47
--- /dev/null
+++ b/include/osmocom/core/Makefile.am
@@ -0,0 +1,12 @@
+osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h bits.h \
+		   bitvec.h statistics.h utils.h \
+		   gsmtap.h write_queue.h \
+		   logging.h rate_ctr.h gsmtap_util.h \
+		   plugin.h crc16.h panic.h process.h msgfile.h \
+		   backtrace.h
+
+if ENABLE_TALLOC
+osmocore_HEADERS += talloc.h
+endif
+
+osmocoredir = $(includedir)/osmocom/core
diff --git a/include/osmocom/core/backtrace.h b/include/osmocom/core/backtrace.h
new file mode 100644
index 0000000..bbbb2c2
--- /dev/null
+++ b/include/osmocom/core/backtrace.h
@@ -0,0 +1,6 @@
+#ifndef _OSMO_BACKTRACE_H_
+#define _OSMO_BACKTRACE_H_
+
+void generate_backtrace();
+
+#endif
diff --git a/include/osmocom/core/bits.h b/include/osmocom/core/bits.h
new file mode 100644
index 0000000..8d4a078
--- /dev/null
+++ b/include/osmocom/core/bits.h
@@ -0,0 +1,45 @@
+#ifndef _OSMO_BITS_H
+#define _OSMO_BITS_H
+
+#include <stdint.h>
+
+typedef uint8_t sbit_t;		/* soft bit (-127...127) */
+typedef uint8_t ubit_t;		/* unpacked bit (0 or 1) */
+typedef uint8_t pbit_t;		/* packed bis (8 bits in a byte) */
+
+/*
+   NOTE on the endianess of pbit_t:
+   Bits in a pbit_t are ordered MSB first, i.e. 0x80 is the first bit.
+   Bit i in a pbit_t array is array[i/8] & (1<<(7-i%8))
+*/
+
+/* determine how many bytes we would need for 'num_bits' packed bits */
+static inline unsigned int osmo_pbit_bytesize(unsigned int num_bits)
+{
+	unsigned int pbit_bytesize = num_bits / 8;
+
+	if (num_bits % 8)
+		pbit_bytesize++;
+
+	return pbit_bytesize;
+}
+
+/* convert unpacked bits to packed bits, return length in bytes */
+int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits);
+
+/* convert packed bits to unpacked bits, return length in bytes */
+int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits);
+
+/* convert unpacked bits to packed bits (extended options but slower),
+ * return length in bytes (max written ofs of output buffer + 1) */
+int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
+                       const ubit_t *in, unsigned int in_ofs,
+                       unsigned int num_bits, int lsb_mode);
+
+/* convert packed bits to unpacked bits (extended options but slower),
+ * return length in bytes (max written ofs of output buffer + 1) */
+int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
+                       const pbit_t *in, unsigned int in_ofs,
+                       unsigned int num_bits, int lsb_mode);
+
+#endif
diff --git a/include/osmocom/core/bitvec.h b/include/osmocom/core/bitvec.h
new file mode 100644
index 0000000..42977fb
--- /dev/null
+++ b/include/osmocom/core/bitvec.h
@@ -0,0 +1,75 @@
+#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(const struct bitvec *bv, unsigned int bitnr);
+
+/* check if the bit is L or H for a given position inside a bitvec */
+enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
+					unsigned int bitnr);
+
+/* get the Nth set bit inside the bit vector */
+unsigned int bitvec_get_nth_set_bit(const 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);
+
+/* get the next bit (low/high) inside a bitvec */
+int bitvec_get_bit_high(struct bitvec *bv);
+
+/* 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);
+
+/* get multiple bits (based on numeric value) from current pos */
+int bitvec_get_uint(struct bitvec *bv, int num_bits);
+
+
+/* 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/osmocom/core/crc16.h b/include/osmocom/core/crc16.h
new file mode 100644
index 0000000..7a51249
--- /dev/null
+++ b/include/osmocom/core/crc16.h
@@ -0,0 +1,34 @@
+/*
+ * This was copied from the linux kernel and adjusted for our types.
+ */
+/*
+ *	crc16.h - CRC-16 routine
+ *
+ * Implements the standard CRC-16:
+ *   Width 16
+ *   Poly  0x8005 (x^16 + x^15 + x^2 + 1)
+ *   Init  0
+ *
+ * Copyright (c) 2005 Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef __CRC16_H
+#define __CRC16_H
+
+#include <stdint.h>
+
+#include <sys/types.h>
+
+extern uint16_t const crc16_table[256];
+
+extern uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len);
+
+static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
+{
+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+#endif /* __CRC16_H */
diff --git a/include/osmocom/core/gsmtap.h b/include/osmocom/core/gsmtap.h
new file mode 100644
index 0000000..236b25a
--- /dev/null
+++ b/include/osmocom/core/gsmtap.h
@@ -0,0 +1,89 @@
+#ifndef _GSMTAP_H
+#define _GSMTAP_H
+
+/* gsmtap header, pseudo-header in front of the actua GSM payload */
+
+/* GSMTAP is a generic header format for GSM protocol captures,
+ * it uses the IANA-assigned UDP port number 4729 and carries
+ * payload in various formats of GSM interfaces such as Um MAC
+ * blocks or Um bursts.
+ *
+ * Example programs generating GSMTAP data are airprobe
+ * (http://airprobe.org/) or OsmocomBB (http://bb.osmocom.org/)
+ */
+
+#include <stdint.h>
+
+#define GSMTAP_VERSION		0x02
+
+#define GSMTAP_TYPE_UM		0x01
+#define GSMTAP_TYPE_ABIS	0x02
+#define GSMTAP_TYPE_UM_BURST	0x03	/* raw burst bits */
+#define GSMTAP_TYPE_SIM		0x04
+#define GSMTAP_TYPE_TETRA_I1		0x05	/* tetra air interface */
+#define GSMTAP_TYPE_TETRA_I1_BURST	0x06	/* tetra air interface */
+
+/* sub-types for TYPE_UM_BURST */
+#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
+
+/* sub-types for TYPE_UM */
+#define GSMTAP_CHANNEL_UNKNOWN	0x00
+#define GSMTAP_CHANNEL_BCCH	0x01
+#define GSMTAP_CHANNEL_CCCH	0x02
+#define GSMTAP_CHANNEL_RACH	0x03
+#define GSMTAP_CHANNEL_AGCH	0x04
+#define GSMTAP_CHANNEL_PCH	0x05
+#define GSMTAP_CHANNEL_SDCCH	0x06
+#define GSMTAP_CHANNEL_SDCCH4	0x07
+#define GSMTAP_CHANNEL_SDCCH8	0x08
+#define GSMTAP_CHANNEL_TCH_F	0x09
+#define GSMTAP_CHANNEL_TCH_H	0x0a
+#define GSMTAP_CHANNEL_ACCH	0x80
+
+/* sub-types for TYPE_TETRA_AIR */
+#define GSMTAP_TETRA_BSCH	0x01
+#define GSMTAP_TETRA_AACH	0x02
+#define GSMTAP_TETRA_SCH_HU	0x03
+#define GSMTAP_TETRA_SCH_HD	0x04
+#define GSMTAP_TETRA_SCH_F	0x05
+#define GSMTAP_TETRA_BNCH	0x06
+#define GSMTAP_TETRA_STCH	0x07
+#define GSMTAP_TETRA_TCH_F	0x08
+
+/* flags for the ARFCN */
+#define GSMTAP_ARFCN_F_PCS	0x8000
+#define GSMTAP_ARFCN_F_UPLINK	0x4000
+#define GSMTAP_ARFCN_MASK	0x3fff
+
+/* IANA-assigned well-known UDP port for GSMTAP messages */
+#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) */
+	int8_t signal_dbm;	/* signal level in dBm */
+	int8_t snr_db;		/* signal/noise ratio in dB */
+
+	uint32_t frame_number;	/* GSM Frame Number (FN) */
+
+	uint8_t sub_type;	/* Type of burst/channel, see above */
+	uint8_t antenna_nr;	/* Antenna Number */
+	uint8_t sub_slot;	/* sub-slot within timeslot */
+	uint8_t res;		/* reserved for future use (RFU) */
+
+} __attribute__((packed));
+
+#endif /* _GSMTAP_H */
diff --git a/include/osmocom/core/gsmtap_util.h b/include/osmocom/core/gsmtap_util.h
new file mode 100644
index 0000000..9644944
--- /dev/null
+++ b/include/osmocom/core/gsmtap_util.h
@@ -0,0 +1,21 @@
+#ifndef _GSMTAP_UTIL_H
+#define _GSMTAP_UTIL_H
+
+#include <stdint.h>
+
+/* convert RSL channel number to GSMTAP channel type */
+uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t rsl_link_id);
+
+/* receive a message from L1/L2 and put it in GSMTAP */
+struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type,
+			    uint8_t ss, uint32_t fn, int8_t signal_dbm,
+			    uint8_t snr, const uint8_t *data, unsigned int len);
+
+/* receive a message from L1/L2 and put it in GSMTAP */
+int gsmtap_sendmsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss,
+		   uint32_t fn, int8_t signal_dbm, uint8_t snr,
+		   const uint8_t *data, unsigned int len);
+
+int gsmtap_init(uint32_t dst_ip);
+
+#endif /* _GSMTAP_UTIL_H */
diff --git a/include/osmocom/core/linuxlist.h b/include/osmocom/core/linuxlist.h
new file mode 100644
index 0000000..fb99c5e
--- /dev/null
+++ b/include/osmocom/core/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/osmocom/core/logging.h b/include/osmocom/core/logging.h
new file mode 100644
index 0000000..db02940
--- /dev/null
+++ b/include/osmocom/core/logging.h
@@ -0,0 +1,154 @@
+#ifndef _OSMOCORE_LOGGING_H
+#define _OSMOCORE_LOGGING_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+
+#define LOG_MAX_CATEGORY	32
+#define LOG_MAX_CTX		8
+#define LOG_MAX_FILTERS	8
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
+#define DEBUGPC(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 1, fmt, ## args)
+#else
+#define DEBUGP(xss, fmt, args...)
+#define DEBUGPC(ss, fmt, args...)
+#endif
+
+
+void logp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
+
+/* new logging interface */
+#define LOGP(ss, level, fmt, args...) \
+	logp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
+#define LOGPC(ss, level, fmt, args...) \
+	logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args)
+
+/* different levels */
+#define LOGL_DEBUG	1	/* debugging information */
+#define LOGL_INFO	3
+#define LOGL_NOTICE	5	/* abnormal/unexpected condition */
+#define LOGL_ERROR	7	/* error condition, requires user action */
+#define LOGL_FATAL	8	/* fatal, program aborted */
+
+#define LOG_FILTER_ALL	0x0001
+
+struct log_category {
+	uint8_t loglevel;
+	uint8_t enabled;
+};
+
+struct log_info_cat {
+	const char *name;
+	const char *color;
+	const char *description;
+	uint8_t loglevel;
+	uint8_t enabled;
+};
+
+/* log context information, passed to filter */
+struct log_context {
+	void *ctx[LOG_MAX_CTX+1];
+};
+
+struct log_target;
+
+typedef int log_filter(const struct log_context *ctx,
+		       struct log_target *target);
+
+struct log_info {
+	/* filter callback function */
+	log_filter *filter_fn;
+
+	/* per-category information */
+	const struct log_info_cat *cat;
+	unsigned int num_cat;
+};
+
+enum log_target_type {
+	LOG_TGT_TYPE_VTY,
+	LOG_TGT_TYPE_SYSLOG,
+	LOG_TGT_TYPE_FILE,
+	LOG_TGT_TYPE_STDERR,
+};
+
+struct log_target {
+        struct llist_head entry;
+
+	int filter_map;
+	void *filter_data[LOG_MAX_FILTERS+1];
+
+	struct log_category categories[LOG_MAX_CATEGORY+1];
+	uint8_t loglevel;
+	int use_color:1;
+	int print_timestamp:1;
+
+	enum log_target_type type;
+
+	union {
+		struct {
+			FILE *out;
+			const char *fname;
+		} tgt_file;
+
+		struct {
+			int priority;
+			int facility;
+		} tgt_syslog;
+
+		struct {
+			void *vty;
+		} tgt_vty;
+	};
+
+        void (*output) (struct log_target *target, unsigned int level,
+			const char *string);
+};
+
+/* use the above macros */
+void logp2(unsigned int subsys, unsigned int level, char *file,
+	   int line, int cont, const char *format, ...)
+				__attribute__ ((format (printf, 6, 7)));
+void log_init(const struct log_info *cat);
+
+/* context management */
+void log_reset_context(void);
+int log_set_context(uint8_t ctx, void *value);
+
+/* filter on the targets */
+void log_set_all_filter(struct log_target *target, int);
+
+void log_set_use_color(struct log_target *target, int);
+void log_set_print_timestamp(struct log_target *target, int);
+void log_set_log_level(struct log_target *target, int log_level);
+void log_parse_category_mask(struct log_target *target, const char* mask);
+int log_parse_level(const char *lvl);
+const char *log_level_str(unsigned int lvl);
+int log_parse_category(const char *category);
+void log_set_category_filter(struct log_target *target, int category,
+			       int enable, int level);
+
+/* management of the targets */
+struct log_target *log_target_create(void);
+void log_target_destroy(struct log_target *target);
+struct log_target *log_target_create_stderr(void);
+struct log_target *log_target_create_file(const char *fname);
+struct log_target *log_target_create_syslog(const char *ident, int option,
+					    int facility);
+int log_target_file_reopen(struct log_target *tgt);
+
+void log_add_target(struct log_target *target);
+void log_del_target(struct log_target *target);
+
+/* Generate command string for VTY use */
+const char *log_vty_command_string(const struct log_info *info);
+const char *log_vty_command_description(const struct log_info *info);
+
+struct log_target *log_target_find(int type, const char *fname);
+extern struct llist_head osmo_log_target_list;
+
+#endif /* _OSMOCORE_LOGGING_H */
diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h
new file mode 100644
index 0000000..57b5d7f
--- /dev/null
+++ b/include/osmocom/core/msgb.h
@@ -0,0 +1,197 @@
+#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 <osmocom/core/linuxlist.h>
+#include <osmocom/core/utils.h>
+
+#define MSGB_DEBUG
+
+struct msgb {
+	struct llist_head list;
+
+	/* Part of which TRX logical channel we were received / transmitted */
+	/* FIXME: move them into the control buffer */
+	struct gsm_bts_trx *trx;
+	struct gsm_lchan *lchan;
+
+	/* the Layer1 header (if any) */
+	unsigned char *l1h;
+	/* the A-bis layer 2 header: OML, RSL(RLL), NS */
+	unsigned char *l2h;
+	/* the layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */
+	unsigned char *l3h;
+	/* the layer 4 header */
+	unsigned char *l4h;
+
+	/* the 'control buffer', large enough to contain 5 pointers */
+	unsigned long cb[5];
+
+	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);
+
+#ifdef MSGB_DEBUG
+#include <osmocom/core/panic.h>
+#define MSGB_ABORT(msg, fmt, args ...) do {		\
+	osmo_panic("msgb(%p): " fmt, msg, ## args);	\
+	} while(0)
+#else
+#define MSGB_ABORT(msg, fmt, args ...)
+#endif
+
+#define msgb_l1(m)	((void *)(m->l1h))
+#define msgb_l2(m)	((void *)(m->l2h))
+#define msgb_l3(m)	((void *)(m->l3h))
+#define msgb_sms(m)	((void *)(m->l4h))
+
+static inline unsigned int msgb_l1len(const struct msgb *msgb)
+{
+	return msgb->tail - (uint8_t *)msgb_l1(msgb);
+}
+
+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 int msgb_tailroom(const struct msgb *msgb)
+{
+	return (msgb->head + msgb->data_len) - msgb->tail;
+}
+
+static inline int msgb_headroom(const struct msgb *msgb)
+{
+	return (msgb->data - msgb->head);
+}
+
+static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
+{
+	unsigned char *tmp = msgb->tail;
+	if (msgb_tailroom(msgb) < (int) len)
+		MSGB_ABORT(msgb, "Not enough tailroom msgb_push (%u < %u)\n",
+			   msgb_tailroom(msgb), len);
+	msgb->tail += len;
+	msgb->len += len;
+	return tmp;
+}
+static inline void msgb_put_u8(struct msgb *msgb, uint8_t word)
+{
+	uint8_t *space = msgb_put(msgb, 1);
+	space[0] = word & 0xFF;
+}
+static inline void msgb_put_u16(struct msgb *msgb, uint16_t word)
+{
+	uint8_t *space = msgb_put(msgb, 2);
+	space[0] = word >> 8 & 0xFF;
+	space[1] = word & 0xFF;
+}
+static inline void msgb_put_u32(struct msgb *msgb, uint32_t word)
+{
+	uint8_t *space = msgb_put(msgb, 4);
+	space[0] = word >> 24 & 0xFF;
+	space[1] = word >> 16 & 0xFF;
+	space[2] = word >> 8 & 0xFF;
+	space[3] = word & 0xFF;
+}
+static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len)
+{
+	unsigned char *tmp = msgb->data;
+	msgb->data += len;
+	msgb->len -= len;
+	return tmp;
+}
+static inline uint8_t msgb_get_u8(struct msgb *msgb)
+{
+	uint8_t *space = msgb_get(msgb, 1);
+	return space[0];
+}
+static inline uint16_t msgb_get_u16(struct msgb *msgb)
+{
+	uint8_t *space = msgb_get(msgb, 2);
+	return space[0] << 8 | space[1];
+}
+static inline uint32_t msgb_get_u32(struct msgb *msgb)
+{
+	uint8_t *space = msgb_get(msgb, 4);
+	return space[0] << 24 | space[1] << 16 | space[2] << 8 | space[3];
+}
+static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
+{
+	if (msgb_headroom(msgb) < (int) len)
+		MSGB_ABORT(msgb, "Not enough headroom msgb_push (%u < %u)\n",
+			   msgb_headroom(msgb), 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;
+}
+
+/* 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)
+{
+	static_assert(size > headroom, headroom_bigger);
+
+	struct msgb *msg = msgb_alloc(size, name);
+	if (msg)
+		msgb_reserve(msg, headroom);
+	return msg;
+}
+
+/* non inline functions to ease binding */
+uint8_t *msgb_data(const struct msgb *msg);
+uint16_t msgb_length(const struct msgb *msg);
+
+
+#endif /* _MSGB_H */
diff --git a/include/osmocom/core/msgfile.h b/include/osmocom/core/msgfile.h
new file mode 100644
index 0000000..92caa9f
--- /dev/null
+++ b/include/osmocom/core/msgfile.h
@@ -0,0 +1,49 @@
+/*
+ * (C) 2010 by Holger Hans Peter Freyther
+ * (C) 2010 by On-Waves
+ * 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 MSG_FILE_H
+#define MSG_FILE_H
+
+#include "linuxlist.h"
+
+/**
+ * One message in the list.
+ */
+struct msg_entry {
+	struct llist_head list;
+
+	/* number for everyone to use */
+	int nr;
+
+	/* data from the file */
+	char *mcc;
+	char *mnc;
+	char *option;
+	char *text;
+};
+
+struct msg_entries {
+	struct llist_head entry;
+};
+
+struct msg_entries *msg_entry_parse(void *ctx, const char *filename);
+
+#endif
diff --git a/include/osmocom/core/panic.h b/include/osmocom/core/panic.h
new file mode 100644
index 0000000..c5a8377
--- /dev/null
+++ b/include/osmocom/core/panic.h
@@ -0,0 +1,11 @@
+#ifndef OSMOCORE_PANIC_H
+#define OSMOCORE_PANIC_H
+
+#include <stdarg.h>
+
+typedef void (*osmo_panic_handler_t)(const char *fmt, va_list args);
+
+void osmo_panic(const char *fmt, ...);
+void osmo_set_panic_handler(osmo_panic_handler_t h);
+
+#endif
diff --git a/include/osmocom/core/plugin.h b/include/osmocom/core/plugin.h
new file mode 100644
index 0000000..98f9b56
--- /dev/null
+++ b/include/osmocom/core/plugin.h
@@ -0,0 +1,6 @@
+#ifndef _OSMO_PLUGIN_H
+#define _OSMO_PLUGIN_H
+
+int plugin_load_all(const char *directory);
+
+#endif
diff --git a/include/osmocom/core/process.h b/include/osmocom/core/process.h
new file mode 100644
index 0000000..2d66382
--- /dev/null
+++ b/include/osmocom/core/process.h
@@ -0,0 +1,6 @@
+#ifndef _OSMO_PROCESS_H
+#define _OSMO_PROCESS_H
+
+int osmo_daemonize(void);
+
+#endif
diff --git a/include/osmocom/core/rate_ctr.h b/include/osmocom/core/rate_ctr.h
new file mode 100644
index 0000000..dba573d
--- /dev/null
+++ b/include/osmocom/core/rate_ctr.h
@@ -0,0 +1,81 @@
+#ifndef _RATE_CTR_H
+#define _RATE_CTR_H
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+
+#define RATE_CTR_INTV_NUM	4
+
+enum rate_ctr_intv {
+	RATE_CTR_INTV_SEC,
+	RATE_CTR_INTV_MIN,
+	RATE_CTR_INTV_HOUR,
+	RATE_CTR_INTV_DAY,
+};
+
+/* for each of the intervals, we keep the following values */
+struct rate_ctr_per_intv {
+	uint64_t last;
+	uint64_t rate;
+};
+
+/* for each actual value, we keep the following data */
+struct rate_ctr {
+	uint64_t current;
+	struct rate_ctr_per_intv intv[RATE_CTR_INTV_NUM];
+};
+
+struct rate_ctr_desc {
+	const char *name;
+	const char *description;
+};
+
+/* Describe a counter group class */
+struct rate_ctr_group_desc {
+	/* The prefix to the name of all counters in this group */
+	const char *group_name_prefix;
+	/* The human-readable description of the group */
+	const char *group_description;
+	/* The number of counters in this group */
+	const unsigned int num_ctr;
+	/* Pointer to array of counter names */
+	const struct rate_ctr_desc *ctr_desc;
+};
+
+/* One instance of a counter group class */
+struct rate_ctr_group {
+	/* Linked list of all counter groups in the system */
+	struct llist_head list;
+	/* Pointer to the counter group class */
+	const struct rate_ctr_group_desc *desc;
+	/* The index of this ctr_group within its class */
+	unsigned int idx;
+	/* Actual counter structures below */
+	struct rate_ctr ctr[0];
+};
+
+/* Allocate a new group of counters according to description */
+struct rate_ctr_group *rate_ctr_group_alloc(void *ctx,
+					    const struct rate_ctr_group_desc *desc,
+					    unsigned int idx);
+
+/* Free the memory for the specified group of counters */
+void rate_ctr_group_free(struct rate_ctr_group *grp);
+
+/* Add a number to the counter */
+void rate_ctr_add(struct rate_ctr *ctr, int inc);
+
+/* Increment the counter by 1 */
+static inline void rate_ctr_inc(struct rate_ctr *ctr)
+{
+	rate_ctr_add(ctr, 1);
+}
+
+/* Initialize the counter module */
+int rate_ctr_init(void *tall_ctx);
+
+struct vty;
+void vty_out_rate_ctr_group(struct vty *vty, const char *prefix,
+			    struct rate_ctr_group *ctrg);
+#endif /* RATE_CTR_H */
diff --git a/include/osmocom/core/select.h b/include/osmocom/core/select.h
new file mode 100644
index 0000000..5ca21c3
--- /dev/null
+++ b/include/osmocom/core/select.h
@@ -0,0 +1,22 @@
+#ifndef _BSC_SELECT_H
+#define _BSC_SELECT_H
+
+#include <osmocom/core/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/osmocom/core/signal.h b/include/osmocom/core/signal.h
new file mode 100644
index 0000000..02d83d2
--- /dev/null
+++ b/include/osmocom/core/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/osmocom/core/statistics.h b/include/osmocom/core/statistics.h
new file mode 100644
index 0000000..1d56054
--- /dev/null
+++ b/include/osmocom/core/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/osmocom/core/talloc.h b/include/osmocom/core/talloc.h
new file mode 100644
index 0000000..f7f7643
--- /dev/null
+++ b/include/osmocom/core/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/osmocom/core/timer.h b/include/osmocom/core/timer.h
new file mode 100644
index 0000000..1966478
--- /dev/null
+++ b/include/osmocom/core/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 <osmocom/core/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/osmocom/core/utils.h b/include/osmocom/core/utils.h
new file mode 100644
index 0000000..0cdf03b
--- /dev/null
+++ b/include/osmocom/core/utils.h
@@ -0,0 +1,30 @@
+#ifndef OSMOCORE_UTIL_H
+#define OSMOCORE_UTIL_H
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#include <stdint.h>
+
+struct value_string {
+	unsigned int value;
+	const char *str;
+};
+
+const char *get_value_string(const struct value_string *vs, uint32_t val);
+int get_string_value(const struct value_string *vs, const char *str);
+
+char bcd2char(uint8_t bcd);
+/* only works for numbers in ascci */
+uint8_t char2bcd(char c);
+
+int hexparse(const char *str, uint8_t *b, int max_len);
+char *hexdump(const unsigned char *buf, int len);
+char *hexdump_nospc(const unsigned char *buf, int len);
+char *ubit_dump(const uint8_t *bits, unsigned int len);
+
+#define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
+
+void osmo_str2lower(char *out, const char *in);
+void osmo_str2upper(char *out, const char *in);
+
+#endif
diff --git a/include/osmocom/core/write_queue.h b/include/osmocom/core/write_queue.h
new file mode 100644
index 0000000..ef244c3
--- /dev/null
+++ b/include/osmocom/core/write_queue.h
@@ -0,0 +1,46 @@
+/* Generic write queue implementation */
+/*
+ * (C) 2010 by Holger Hans Peter Freyther
+ * (C) 2010 by On-Waves
+ *
+ * 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 write_queue_h
+#define write_queue_h
+
+#include "select.h"
+#include "msgb.h"
+
+struct write_queue {
+	struct bsc_fd bfd;
+	unsigned int max_length;
+	unsigned int current_length;
+
+	struct llist_head msg_queue;
+
+	int (*read_cb)(struct bsc_fd *fd);
+	int (*write_cb)(struct bsc_fd *fd, struct msgb *msg);
+	int (*except_cb)(struct bsc_fd *fd);
+};
+
+void write_queue_init(struct write_queue *queue, int max_length);
+void write_queue_clear(struct write_queue *queue);
+int write_queue_enqueue(struct write_queue *queue, struct msgb *data);
+int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what);
+
+#endif
diff --git a/include/osmocom/crypt/gprs_cipher.h b/include/osmocom/crypt/gprs_cipher.h
index 3e514ec..3051071 100644
--- a/include/osmocom/crypt/gprs_cipher.h
+++ b/include/osmocom/crypt/gprs_cipher.h
@@ -1,7 +1,7 @@
 #ifndef _GPRS_CIPHER_H
 #define _GPRS_CIPHER_H
 
-#include <osmocore/linuxlist.h>
+#include <osmocom/core/linuxlist.h>
 
 #define GSM0464_CIPH_MAX_BLOCK	1523
 
diff --git a/include/osmocom/gsm/Makefile.am b/include/osmocom/gsm/Makefile.am
new file mode 100644
index 0000000..8685fc9
--- /dev/null
+++ b/include/osmocom/gsm/Makefile.am
@@ -0,0 +1,6 @@
+osmogsm_HEADERS = comp128.h gsm0808.h gsm48_ie.h mncc.h rxlev_stat.h \
+		  gsm0480.h gsm48.h gsm_utils.h rsl.h tlv.h
+
+SUBDIRS = protocol
+
+osmogsmdir = $(includedir)/osmocom/gsm
diff --git a/include/osmocom/gsm/comp128.h b/include/osmocom/gsm/comp128.h
new file mode 100644
index 0000000..c37808f
--- /dev/null
+++ b/include/osmocom/gsm/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/osmocom/gsm/gsm0480.h b/include/osmocom/gsm/gsm0480.h
new file mode 100644
index 0000000..d6626d6
--- /dev/null
+++ b/include/osmocom/gsm/gsm0480.h
@@ -0,0 +1,26 @@
+#ifndef gsm0480_h
+#define gsm0480_h
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/protocol/gsm_04_80.h>
+
+#define MAX_LEN_USSD_STRING	31
+
+struct ussd_request {
+	char text[MAX_LEN_USSD_STRING + 1];
+	uint8_t transaction_id;
+	uint8_t invoke_id;
+};
+
+int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len,
+				struct ussd_request *request);
+
+struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const char *text);
+struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *text);
+struct msgb *gsm0480_create_notifySS(const char *text);
+
+int gsm0480_wrap_invoke(struct msgb *msg, int op, int link_id);
+int gsm0480_wrap_facility(struct msgb *msg);
+
+#endif
diff --git a/include/osmocom/gsm/gsm0808.h b/include/osmocom/gsm/gsm0808.h
new file mode 100644
index 0000000..1d85377
--- /dev/null
+++ b/include/osmocom/gsm/gsm0808.h
@@ -0,0 +1,46 @@
+/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009,2010 by On-Waves
+ * 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 OSMOCORE_GSM0808_H
+#define OSMOCORE_GSM0808_H
+
+#include "tlv.h"
+
+struct msgb;
+
+struct msgb *gsm0808_create_layer3(struct msgb *msg, uint16_t netcode, uint16_t countrycode, int lac, uint16_t ci);
+struct msgb *gsm0808_create_reset(void);
+struct msgb *gsm0808_create_clear_command(uint8_t reason);
+struct msgb *gsm0808_create_clear_complete(void);
+struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id);
+struct msgb *gsm0808_create_cipher_reject(uint8_t cause);
+struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark, uint8_t length);
+struct msgb *gsm0808_create_sapi_reject(uint8_t link_id);
+struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause,
+						 uint8_t chosen_channel, uint8_t encr_alg_id,
+						 uint8_t speech_mode);
+struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause);
+struct msgb *gsm0808_create_clear_rqst(uint8_t cause);
+
+struct msgb *gsm0808_create_dtap(struct msgb *msg, uint8_t link_id);
+void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id);
+
+const struct tlv_definition *gsm0808_att_tlvdef();
+
+#endif
diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h
new file mode 100644
index 0000000..1e9403b
--- /dev/null
+++ b/include/osmocom/gsm/gsm48.h
@@ -0,0 +1,36 @@
+#ifndef _OSMOCORE_GSM48_H
+#define _OSMOCORE_GSM48_H
+
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm48_ie.h>
+
+/* A parsed GPRS routing area */
+struct gprs_ra_id {
+	uint16_t	mnc;
+	uint16_t	mcc;
+	uint16_t	lac;
+	uint8_t		rac;
+};
+
+extern const struct tlv_definition gsm48_att_tlvdef;
+extern const struct tlv_definition gsm48_rr_att_tlvdef;
+extern const struct tlv_definition gsm48_mm_att_tlvdef;
+const char *gsm48_cc_state_name(uint8_t state);
+const char *gsm48_cc_msg_name(uint8_t msgtype);
+const char *rr_cause_name(uint8_t cause);
+
+void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
+			uint16_t mnc, uint16_t lac);
+int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi);
+int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi);
+
+/* Convert Mobile Identity (10.5.1.4) to string */
+int gsm48_mi_to_string(char *string, const int str_len,
+			const uint8_t *mi, const int mi_len);
+
+/* Parse Routeing Area Identifier */
+void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf);
+int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid);
+
+#endif
diff --git a/include/osmocom/gsm/gsm48_ie.h b/include/osmocom/gsm/gsm48_ie.h
new file mode 100644
index 0000000..f4fce25
--- /dev/null
+++ b/include/osmocom/gsm/gsm48_ie.h
@@ -0,0 +1,117 @@
+#ifndef _OSMOCORE_GSM48_IE_H
+#define _OSMOCORE_GSM48_IE_H
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/mncc.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
+int gsm48_decode_bcd_number(char *output, int output_len,
+			    const uint8_t *bcd_lv, int h_len);
+
+/* convert a ASCII phone number to 'called/calling/connect party BCD number' */
+int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
+			    int h_len, const char *input);
+/* decode 'bearer capability' */
+int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
+			     const uint8_t *lv);
+/* encode 'bearer capability' */
+int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
+			     const struct gsm_mncc_bearer_cap *bcap);
+/* decode 'call control cap' */
+int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv);
+/* encode 'call control cap' */
+int gsm48_encode_cccap(struct msgb *msg,
+			const struct gsm_mncc_cccap *ccap);
+/* decode 'called party BCD number' */
+int gsm48_decode_called(struct gsm_mncc_number *called,
+			 const uint8_t *lv);
+/* encode 'called party BCD number' */
+int gsm48_encode_called(struct msgb *msg,
+			 const struct gsm_mncc_number *called);
+/* decode callerid of various IEs */
+int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
+			 const uint8_t *lv);
+/* encode callerid of various IEs */
+int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
+			   const struct gsm_mncc_number *callerid);
+/* decode 'cause' */
+int gsm48_decode_cause(struct gsm_mncc_cause *cause,
+			const uint8_t *lv);
+/* encode 'cause' */
+int gsm48_encode_cause(struct msgb *msg, int lv_only,
+			const struct gsm_mncc_cause *cause);
+/* decode 'calling number' */
+int gsm48_decode_calling(struct gsm_mncc_number *calling,
+			 const uint8_t *lv);
+/* encode 'calling number' */
+int gsm48_encode_calling(struct msgb *msg, 
+			  const struct gsm_mncc_number *calling);
+/* decode 'connected number' */
+int gsm48_decode_connected(struct gsm_mncc_number *connected,
+			 const uint8_t *lv);
+/* encode 'connected number' */
+int gsm48_encode_connected(struct msgb *msg,
+			    const struct gsm_mncc_number *connected);
+/* decode 'redirecting number' */
+int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
+			 const uint8_t *lv);
+/* encode 'redirecting number' */
+int gsm48_encode_redirecting(struct msgb *msg,
+			      const struct gsm_mncc_number *redirecting);
+/* decode 'facility' */
+int gsm48_decode_facility(struct gsm_mncc_facility *facility,
+			   const uint8_t *lv);
+/* encode 'facility' */
+int gsm48_encode_facility(struct msgb *msg, int lv_only,
+			   const struct gsm_mncc_facility *facility);
+/* decode 'notify' */
+int gsm48_decode_notify(int *notify, const uint8_t *v);
+/* encode 'notify' */
+int gsm48_encode_notify(struct msgb *msg, int notify);
+/* decode 'signal' */
+int gsm48_decode_signal(int *signal, const uint8_t *v);
+/* encode 'signal' */
+int gsm48_encode_signal(struct msgb *msg, int signal);
+/* decode 'keypad' */
+int gsm48_decode_keypad(int *keypad, const uint8_t *lv);
+/* encode 'keypad' */
+int gsm48_encode_keypad(struct msgb *msg, int keypad);
+/* decode 'progress' */
+int gsm48_decode_progress(struct gsm_mncc_progress *progress,
+			   const uint8_t *lv);
+/* encode 'progress' */
+int gsm48_encode_progress(struct msgb *msg, int lv_only,
+			   const struct gsm_mncc_progress *p);
+/* decode 'user-user' */
+int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
+			   const uint8_t *lv);
+/* encode 'useruser' */
+int gsm48_encode_useruser(struct msgb *msg, int lv_only,
+			   const struct gsm_mncc_useruser *uu);
+/* decode 'ss version' */
+int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
+			    const uint8_t *lv);
+/* encode 'ss version' */
+int gsm48_encode_ssversion(struct msgb *msg,
+			   const struct gsm_mncc_ssversion *ssv);
+/* decode 'more data' does not require a function, because it has no value */
+/* encode 'more data' */
+int gsm48_encode_more(struct msgb *msg);
+
+/* structure of one frequency */
+struct gsm_sysinfo_freq {
+	/* if the frequency included in the sysinfo */
+	uint8_t	mask;
+};
+
+/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
+int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd,
+			   uint8_t len, uint8_t mask, uint8_t frqt);
+
+#endif
diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h
new file mode 100644
index 0000000..19adb70
--- /dev/null
+++ b/include/osmocom/gsm/gsm_utils.h
@@ -0,0 +1,117 @@
+/* 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-2010 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>
+
+#define ADD_MODULO(sum, delta, modulo) do {	\
+	if ((sum += delta) >= modulo)		\
+		sum -= modulo;			\
+	} while (0)
+
+#define GSM_MAX_FN	(26*51*2048)
+
+struct gsm_time {
+	uint32_t	fn;	/* FN count */
+	uint16_t	t1;	/* FN div (26*51) */
+	uint8_t		t2;	/* FN modulo 26 */
+	uint8_t		t3;	/* FN modulo 51 */
+	uint8_t		tc;
+};
+
+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,
+};
+
+const char *gsm_band_name(enum gsm_band band);
+enum gsm_band gsm_band_parse(const char *mhz);
+
+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.1.6 */
+static inline int ms_cm2_a5n_support(uint8_t *cm2, int n) {
+	switch (n) {
+		case 0: return 1;
+		case 1: return (cm2[0] & (1<<3)) ? 0 : 1;
+		case 2: return (cm2[2] & (1<<0)) ? 1 : 0;
+		case 3: return (cm2[2] & (1<<1)) ? 1 : 0;
+		default:
+			return 0;
+	}
+}
+
+/* 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];
+}
+
+#define	ARFCN_PCS	0x8000
+#define	ARFCN_UPLINK	0x4000
+#define	ARFCN_FLAG_MASK	0xf000	/* Reserve the upper 5 bits for flags */
+
+enum gsm_band gsm_arfcn2band(uint16_t arfcn);
+
+/* Convert an ARFCN to the frequency in MHz * 10 */
+uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink);
+
+/* Convert from frame number to GSM time */
+void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn);
+
+/* Convert from GSM time to frame number */
+uint32_t gsm_gsmtime2fn(struct gsm_time *time);
+
+/* GSM TS 03.03 Chapter 2.6 */
+enum gprs_tlli_type {
+	TLLI_LOCAL,
+	TLLI_FOREIGN,
+	TLLI_RANDOM,
+	TLLI_AUXILIARY,
+	TLLI_RESERVED,
+};
+
+/* TS 03.03 Chapter 2.6 */
+int gprs_tlli_type(uint32_t tlli);
+
+uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type);
+
+#endif
diff --git a/include/osmocom/gsm/mncc.h b/include/osmocom/gsm/mncc.h
new file mode 100644
index 0000000..a094bb9
--- /dev/null
+++ b/include/osmocom/gsm/mncc.h
@@ -0,0 +1,71 @@
+#ifndef _OSMOCORE_MNCC_H
+#define _OSMOCORE_MNCC_H
+
+#define GSM_MAX_FACILITY       128
+#define GSM_MAX_SSVERSION      128
+#define GSM_MAX_USERUSER       128
+
+/* Expanded fields from GSM TS 04.08, Table 10.5.102 */
+struct gsm_mncc_bearer_cap {
+	int		transfer;	/* Information Transfer Capability */
+	int 		mode;		/* Transfer Mode */
+	int		coding;		/* Coding Standard */
+	int		radio;		/* Radio Channel Requirement */
+	int		speech_ctm;	/* CTM text telephony indication */
+	int		speech_ver[8];	/* Speech version indication */
+};
+
+struct gsm_mncc_number {
+	int 		type;
+	int 		plan;
+	int		present;
+	int		screen;
+	char		number[33];
+};
+
+struct gsm_mncc_cause {
+	int		location;
+	int		coding;
+	int		rec;
+	int		rec_val;
+	int		value;
+	int		diag_len;
+	char		diag[32];
+};
+
+struct gsm_mncc_useruser {
+	int		proto;
+	char		info[GSM_MAX_USERUSER + 1]; /* + termination char */
+};
+
+struct gsm_mncc_progress {
+	int		coding;
+	int		location;
+	int 		descr;
+};
+
+struct gsm_mncc_facility {
+	int		len;
+	char		info[GSM_MAX_FACILITY];
+};
+
+struct gsm_mncc_ssversion {
+	int		len;
+	char		info[GSM_MAX_SSVERSION];
+};
+
+struct gsm_mncc_cccap {
+	int		dtmf;
+	int		pcp;
+};
+
+enum {
+	GSM_MNCC_BCAP_SPEECH	= 0,
+	GSM_MNCC_BCAP_UNR_DIG	= 1,
+	GSM_MNCC_BCAP_AUDIO	= 2,
+	GSM_MNCC_BCAP_FAX_G3	= 3,
+	GSM_MNCC_BCAP_OTHER_ITC = 5,
+	GSM_MNCC_BCAP_RESERVED	= 7,
+};
+
+#endif
diff --git a/include/osmocom/gsm/protocol/Makefile.am b/include/osmocom/gsm/protocol/Makefile.am
new file mode 100644
index 0000000..8483f10
--- /dev/null
+++ b/include/osmocom/gsm/protocol/Makefile.am
@@ -0,0 +1,6 @@
+osmogsm_proto_HEADERS = gsm_03_41.h \
+			gsm_04_08.h gsm_04_11.h gsm_04_12.h gsm_04_80.h \
+			gsm_08_08.h gsm_08_58.h \
+			gsm_12_21.h
+
+osmogsm_protodir = $(includedir)/osmocom/gsm/protocol
diff --git a/include/osmocom/gsm/protocol/gsm_03_41.h b/include/osmocom/gsm/protocol/gsm_03_41.h
new file mode 100644
index 0000000..54365cb
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_03_41.h
@@ -0,0 +1,51 @@
+#ifndef PROTO_GSM_03_41_H
+#define PROTO_GSM_03_41_H
+
+#include <stdint.h>
+
+/* GSM TS 03.41 definitions also TS 23.041*/
+
+/* Chapter 9.3.2 */
+struct gsm341_ms_message {
+	struct {
+		uint8_t code_hi:6;
+		uint8_t gs:2;
+		uint8_t update:4;
+		uint8_t code_lo:4;
+	} serial;
+	uint16_t msg_id;
+	struct {
+		uint8_t language:4;
+		uint8_t group:4;
+	} dcs;
+	struct {
+		uint8_t total:4;
+		uint8_t current:4;
+	} page;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 9.4.1.3 */
+struct gsm341_etws_message {
+	struct {
+		uint8_t code_hi:4;
+		uint8_t popup:1;
+		uint8_t alert:1;
+		uint8_t gs:2;
+		uint8_t update:4;
+		uint8_t code_lo:4;
+	} serial;
+	uint16_t msg_id;
+	uint16_t warning_type;
+	uint8_t data[0];
+} __attribute__((packed));
+
+#define GSM341_MSG_CODE(ms) ((ms)->serial.code_lo | ((ms)->serial.code_hi << 4))
+
+/* Section 9.3.2.1 - Geographical Scope */
+#define GSM341_GS_CELL_WIDE_IMMED	0
+#define GSM341_GS_PLMN_WIDE		1
+#define GSM341_GS_LA_WIDE		2
+#define GSM341_GS_CELL_WIDE		3
+
+#endif /* PROTO_GSM_03_41_H */
diff --git a/include/osmocom/gsm/protocol/gsm_04_08.h b/include/osmocom/gsm/protocol/gsm_04_08.h
new file mode 100644
index 0000000..3ad7dfd
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_04_08.h
@@ -0,0 +1,1262 @@
+#ifndef PROTO_GSM_04_08_H
+#define PROTO_GSM_04_08_H
+
+#include <stdint.h>
+
+/* GSM TS 04.08  definitions */
+struct gsm_lchan;
+
+/* Chapter 10.5.1.5 */
+struct gsm48_classmark1 {
+	uint8_t pwr_lev:3,
+		 a5_1:1,
+		 es_ind:1,
+		 rev_lev:2,
+		 spare:1;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.1.6 */
+struct gsm48_classmark2 {
+	uint8_t pwr_lev:3,
+		 a5_1:1,
+		 es_ind:1,
+		 rev_lev:2,
+		 spare:1;
+	uint8_t	fc:1,
+		 vgcs:1,
+		 vbs:1,
+		 sm_cap:1,
+		 ss_scr:2,
+		 ps_cap:1,
+		 spare2:1;
+	uint8_t	a5_2:1,
+		 a5_3:1,
+		 cmsp:1,
+		 solsa:1,
+		 spare3:1,
+		 lcsva_cap:1,
+		 spare4:1,
+		 cm3:1;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.1b.3 */
+struct gsm48_range_1024 {
+	uint8_t	w1_hi:2,
+		 f0:1,
+		 form_id:5;
+	uint8_t	w1_lo;
+	uint8_t	w2_hi;
+	uint8_t	w3_hi:7,
+		 w2_lo:1;
+	uint8_t	w4_hi:6,
+		 w3_lo:2;
+	uint8_t	w5_hi:6,
+		 w4_lo:2;
+	uint8_t	w6_hi:6,
+		 w5_lo:2;
+	uint8_t	w7_hi:6,
+		 w6_lo:2;
+	uint8_t	w8_hi:6,
+		 w7_lo:2;
+	uint8_t	w9:7,
+		 w8_lo:1;
+	uint8_t	w11_hi:1,
+		 w10:7;
+	uint8_t	w12_hi:2,
+		 w11_lo:6;
+	uint8_t	w13_hi:3,
+		 w12_lo:5;
+	uint8_t	w14_hi:4,
+		 w13_lo:4;
+	uint8_t	w15_hi:5,
+		 w14_lo:3;
+	uint8_t	w16:6,
+		 w15_lo:2;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.1b.4 */
+struct gsm48_range_512 {
+	uint8_t	orig_arfcn_hi:1,
+		 form_id:7;
+	uint8_t	orig_arfcn_mid;
+	uint8_t	w1_hi:7,
+		 orig_arfcn_lo:1;
+	uint8_t	w2_hi:6,
+		 w1_lo:2;
+	uint8_t	w3_hi:6,
+		 w2_lo:2;
+	uint8_t	w4_hi:6,
+		 w3_lo:2;
+	uint8_t	w5:7,
+		 w4_lo:1;
+	uint8_t	w7_hi:1,
+		 w6:7;
+	uint8_t	w8_hi:2,
+		 w7_lo:6;
+	uint8_t	w9_hi:4,
+		 w8_lo:4;
+	uint8_t	w10:6,
+		 w9_lo:2;
+	uint8_t	w12_hi:2,
+		 w11:6;
+	uint8_t	w13_hi:4,
+		 w12_lo:4;
+	uint8_t	w14:6,
+		 w13_lo:2;
+	uint8_t	w16_hi:2,
+		 w15:6;
+	uint8_t	w17:5,
+		 w16_lo:3;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.1b.5 */
+struct gsm48_range_256 {
+	uint8_t	orig_arfcn_hi:1,
+		 form_id:7;
+	uint8_t	orig_arfcn_mid;
+	uint8_t	w1_hi:7,
+		 orig_arfcn_lo:1;
+	uint8_t	w2:7,
+		 w1_lo:1;
+	uint8_t	w4_hi:1,
+		 w3:7;
+	uint8_t	w5_hi:3,
+		 w4_lo:5;
+	uint8_t	w6_hi:5,
+		 w5_lo:3;
+	uint8_t	w8_hi:1,
+		 w7:6,
+		 w6_lo:1;
+	uint8_t	w9_hi:4,
+		 w8_lo:4;
+	uint8_t	w11_hi:2,
+		 w10:5,
+		 w9_lo:1;
+	uint8_t	w12:5,
+		 w11_lo:3;
+	uint8_t	w14_hi:3,
+		 w13:5;
+	uint8_t	w16_hi:1,
+		 w15:5,
+		 w14_lo:2;
+	uint8_t	w18_hi:1,
+		 w17:4,
+		 w16_lo:3;
+	uint8_t	w20_hi:1,
+		 w19:4,
+		 w18_lo:3;
+	uint8_t	spare:1,
+		 w21:4,
+		 w20_lo:3;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.1b.6 */
+struct gsm48_range_128 {
+	uint8_t	orig_arfcn_hi:1,
+		 form_id:7;
+	uint8_t	orig_arfcn_mid;
+	uint8_t	w1:7,
+		 orig_arfcn_lo:1;
+	uint8_t	w3_hi:2,
+		 w2:6;
+	uint8_t	w4_hi:4,
+		 w3_lo:4;
+	uint8_t	w6_hi:2,
+		 w5:5,
+		 w4_lo:1;
+	uint8_t	w7:5,
+		 w6_lo:3;
+	uint8_t	w9:4,
+		 w8:4;
+	uint8_t	w11:4,
+		 w10:4;
+	uint8_t	w13:4,
+		 w12:4;
+	uint8_t	w15:4,
+		 w14:4;
+	uint8_t	w18_hi:2,
+		 w17:3,
+		 w16:3;
+	uint8_t	w21_hi:1,
+		 w20:3,
+		 w19:3,
+		 w18_lo:1;
+	uint8_t	w23:3,
+		 w22:3,
+		 w21_lo:2;
+	uint8_t	w26_hi:2,
+		 w25:3,
+		 w24:3;
+	uint8_t	spare:1,
+		 w28:3,
+		 w27:3,
+		 w26_lo:1;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.1b.7 */
+struct gsm48_var_bit {
+	uint8_t	orig_arfcn_hi:1,
+		 form_id:7;
+	uint8_t	orig_arfcn_mid;
+	uint8_t	rrfcn1_7:7,
+		 orig_arfcn_lo:1;
+	uint8_t rrfcn8_111[13];
+} __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.20 */
+struct gsm48_meas_res {
+	uint8_t	rxlev_full:6,
+		 dtx_used:1,
+		 ba_used:1;
+	uint8_t	rxlev_sub:6,
+		 meas_valid:1,
+		 spare:1;
+	uint8_t	no_nc_n_hi:1,
+		 rxqual_sub:3,
+		 rxqual_full:3,
+		 spare2:1;
+	uint8_t	rxlev_nc1:6,
+		 no_nc_n_lo:2;
+	uint8_t	bsic_nc1_hi:3,
+		 bcch_f_nc1:5;
+	uint8_t	rxlev_nc2_hi:5,
+		 bsic_nc1_lo:3;
+	uint8_t	bsic_nc2_hi:2,
+		 bcch_f_nc2:5,
+		 rxlev_nc2_lo:1;
+	uint8_t	rxlev_nc3_hi:4,
+		 bsic_nc2_lo:4;
+	uint8_t	bsic_nc3_hi:1,
+		 bcch_f_nc3:5,
+		 rxlev_nc3_lo:2;
+	uint8_t	rxlev_nc4_hi:3,
+		 bsic_nc3_lo:5;
+	uint8_t	bcch_f_nc4:5,
+		 rxlev_nc4_lo:3;
+	uint8_t	rxlev_nc5_hi:2,
+		 bsic_nc4:6;
+	uint8_t	bcch_f_nc5_hi:4,
+		 rxlev_nc5_lo:4;
+	uint8_t	rxlev_nc6_hi:1,
+		 bsic_nc5:6,
+		 bcch_f_nc5_lo:1;
+	uint8_t	bcch_f_nc6_hi:3,
+		 rxlev_nc6_lo:5;
+	uint8_t	bsic_nc6:6,
+		 bcch_f_nc6_lo:2;
+} __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.28(a) */
+struct gsm48_power_cmd {
+	uint8_t power_level:5,
+		 spare:2,
+		 atc:1;
+} __attribute__((packed));
+
+/* Chapter 10.5.2.29 */
+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));
+
+
+/* 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 10.5.2.38 */
+struct gsm48_start_time {
+	uint8_t t3_high:3,
+		 t1:5;
+	uint8_t t2:5,
+		 t3_low:3;
+} __attribute__ ((packed));
+
+/* Chapter 10.5.2.39 */
+struct gsm48_sync_ind {
+	uint8_t si:2,
+		 rot:1,
+		 nci:1,
+		 sync_ie:4;
+} __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 9.1.13 */
+struct gsm48_frq_redef {
+	/* Semantic is from 10.5.2.5a */
+	struct gsm48_chan_desc chan_desc;
+	uint8_t mob_alloc_len;
+	uint8_t mob_alloc[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 9.1.25 */
+struct gsm48_pag_resp {
+	uint8_t spare:4,
+		 key_seq:4;
+	uint32_t classmark2;
+	uint8_t mi_len;
+	uint8_t mi[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.3 */
+struct gsm48_auth_resp {
+	uint8_t sres[4];
+} __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));
+
+/* 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.33 System information Type 2bis */
+struct gsm48_system_information_type_2bis {
+	struct gsm48_system_information_type_header header;
+	uint8_t bcch_frequency_list[16];
+	struct gsm48_rach_control rach_control;
+	uint8_t rest_octets[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.34 System information Type 2ter */
+struct gsm48_system_information_type_2ter {
+	struct gsm48_system_information_type_header header;
+	uint8_t ext_bcch_frequency_list[16];
+	uint8_t rest_octets[0];
+} __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.38 System information Type 5bis */
+struct gsm48_system_information_type_5bis {
+        uint8_t rr_protocol_discriminator :4,
+		 skip_indicator:4;
+	uint8_t system_information;
+	uint8_t bcch_frequency_list[16];
+} __attribute__ ((packed));
+
+/* Section 9.1.39 System information Type 5ter */
+struct gsm48_system_information_type_5ter {
+        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 9.1.1 */
+struct gsm48_add_ass {
+	/* Semantic is from 10.5.2.5 */
+	struct gsm48_chan_desc chan_desc;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Section 9.1.3 */
+struct gsm48_ass_cpl {
+	uint8_t rr_cause;
+} __attribute__((packed));
+
+/* Section 9.1.4 */
+struct gsm48_ass_fail {
+	uint8_t rr_cause;
+} __attribute__((packed));
+
+/* Section 9.1.3 */
+struct gsm48_ho_cpl {
+	uint8_t rr_cause;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Section 9.1.4 */
+struct gsm48_ho_fail {
+	uint8_t rr_cause;
+} __attribute__((packed));
+
+/* Section 9.1.7 */
+struct gsm48_chan_rel {
+	uint8_t rr_cause;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Section 9.1.9 */
+struct gsm48_cip_mode_cmd {
+	uint8_t sc:1,
+		 alg_id:3,
+		 cr:1,
+		 spare:3;
+} __attribute__((packed));
+
+/* Section 9.1.11 */
+struct gsm48_cm_change {
+	uint8_t cm2_len;
+	struct gsm48_classmark2 cm2;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Section 9.1.19 */
+struct gsm48_imm_ass_ext {
+	uint8_t l2_plen;
+	uint8_t proto_discr;
+	uint8_t msg_type;
+	uint8_t page_mode;
+	struct gsm48_chan_desc chan_desc1;
+	struct gsm48_req_ref req_ref1;
+	uint8_t timing_advance1;
+	struct gsm48_chan_desc chan_desc2;
+	struct gsm48_req_ref req_ref2;
+	uint8_t timing_advance2;
+	uint8_t mob_alloc_len;
+	uint8_t mob_alloc[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.20 */
+struct gsm48_imm_ass_rej {
+	uint8_t l2_plen;
+	uint8_t proto_discr;
+	uint8_t msg_type;
+	uint8_t page_mode;
+	struct gsm48_req_ref req_ref1;
+	uint8_t wait_ind1;
+	struct gsm48_req_ref req_ref2;
+	uint8_t wait_ind2;
+	struct gsm48_req_ref req_ref3;
+	uint8_t wait_ind3;
+	struct gsm48_req_ref req_ref4;
+	uint8_t wait_ind4;
+	uint8_t rest[0];
+} __attribute__ ((packed));
+
+/* Section 9.1.22 */
+struct gsm48_paging1 {
+	uint8_t l2_plen;
+	uint8_t proto_discr;
+	uint8_t msg_type;
+	uint8_t pag_mode:2,
+		 spare:2,
+		 cneed1:2,
+		 cneed2:2;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Section 9.1.23 */
+struct gsm48_paging2 {
+	uint8_t l2_plen;
+	uint8_t proto_discr;
+	uint8_t msg_type;
+	uint8_t pag_mode:2,
+		 spare:2,
+		 cneed1:2,
+		 cneed2:2;
+	uint32_t tmsi1;
+	uint32_t tmsi2;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Section 9.1.24 */
+struct gsm48_paging3 {
+	uint8_t l2_plen;
+	uint8_t proto_discr;
+	uint8_t msg_type;
+	uint8_t pag_mode:2,
+		 spare:2,
+		 cneed1:2,
+		 cneed2:2;
+	uint32_t tmsi1;
+	uint32_t tmsi2;
+	uint32_t tmsi3;
+	uint32_t tmsi4;
+	uint8_t cneed3:2,
+		 cneed4:2,
+		 spare2:4;
+	uint8_t rest[0];
+} __attribute__((packed));
+
+/* Section 9.1.25 */
+struct gsm48_pag_rsp {
+	uint8_t key_seq:3,
+		 spare:5;
+	uint8_t cm2_len;
+	struct gsm48_classmark2 cm2;
+	uint8_t data[0];
+} __attribute__((packed));
+
+/* Section 9.1.29 */
+struct gsm48_rr_status {
+	uint8_t rr_cause;
+} __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.3.3 CM service type */
+#define GSM48_CMSERV_MO_CALL_PACKET	1
+#define GSM48_CMSERV_EMERGENCY		2
+#define GSM48_CMSERV_SMS		4
+#define GSM48_CMSERV_SUP_SERV		8
+#define GSM48_CMSERV_VGCS		9
+#define GSM48_CMSERV_VBS		10
+#define GSM48_CMSERV_LOC_SERV		11
+
+/* 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_MOBILE_ID	0x17	/* 10.5.1.4 */
+#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 */
+/* RR elements */
+#define GSM48_IE_VGCS_TARGET	0x01
+//#define GSM48_IE_VGCS_T_MODE_I	0x01
+#define GSM48_IE_FRQSHORT_AFTER	0x02
+#define GSM48_IE_MUL_RATE_CFG	0x03	/* 10.5.2.21aa */
+#define GSM48_IE_FREQ_L_AFTER	0x05
+#define GSM48_IE_MSLOT_DESC	0x10
+#define GSM48_IE_CHANMODE_2	0x11
+#define GSM48_IE_FRQSHORT_BEFORE 0x12
+//#define GSM48_IE_FRQSHORT_BEFOR 0x12
+#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
+#define GSM48_IE_MA_AFTER	0x72
+#define GSM48_IE_START_TIME	0x7c
+#define GSM48_IE_FREQ_L_BEFORE	0x19
+//#define GSM48_IE_FRQLIST_BEFORE	0x19
+#define GSM48_IE_CH_DESC_1_BEFORE	0x1c
+//#define GSM48_IE_CHDES_1_BEFORE 0x1c
+#define GSM48_IE_CH_DESC_2_BEFORE	0x1d
+//#define GSM48_IE_CHDES_2_BEFORE	0x1d
+#define GSM48_IE_F_CH_SEQ_BEFORE	0x1e
+//#define GSM48_IE_FRQSEQ_BEFORE	0x1e
+#define GSM48_IE_CLASSMARK3	0x20
+#define GSM48_IE_MA_BEFORE	0x21
+#define GSM48_IE_RR_PACKET_UL	0x22
+#define GSM48_IE_RR_PACKET_DL	0x23
+#define GSM48_IE_CELL_CH_DESC	0x62
+#define GSM48_IE_CHANMODE_1	0x63
+#define GSM48_IE_CHDES_2_AFTER	0x64
+#define GSM48_IE_MODE_SEC_CH	0x66
+#define GSM48_IE_F_CH_SEQ_AFTER	0x69
+#define GSM48_IE_MA_AFTER	0x72
+#define GSM48_IE_BA_RANGE	0x73
+#define GSM48_IE_GROUP_CHDES	0x74
+#define GSM48_IE_BA_LIST_PREF	0x75
+#define GSM48_IE_MOB_OVSERV_DIF	0x77
+#define GSM48_IE_REALTIME_DIFF	0x7b
+#define GSM48_IE_START_TIME	0x7c
+#define GSM48_IE_TIMING_ADVANCE	0x7d
+#define GSM48_IE_GROUP_CIP_SEQ	0x80
+#define GSM48_IE_CIP_MODE_SET	0x90
+#define GSM48_IE_GPRS_RESUMPT	0xc0
+#define GSM48_IE_SYNC_IND	0xd0
+/* System Information 4 (types are equal IEs above) */
+#define GSM48_IE_CBCH_CHAN_DESC	0x64
+#define GSM48_IE_CBCH_MOB_AL	0x72
+
+/* Additional MM elements */
+#define GSM48_IE_LOCATION_AREA	0x13
+#define GSM48_IE_PRIORITY_LEV	0x80
+#define GSM48_IE_FOLLOW_ON_PROC	0xa1
+#define GSM48_IE_CTS_PERMISSION	0xa2
+
+/* 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
+#define GSM48_T303_MS	30, 0
+#define GSM48_T305_MS	30, 0
+#define GSM48_T308_MS	30, 0
+#define GSM48_T310_MS	30, 0
+#define GSM48_T313_MS	30, 0
+#define GSM48_T323_MS	30, 0
+#define GSM48_T332_MS	30, 0
+#define GSM48_T335_MS	30, 0
+
+/* Chapter 5.1.2.2 */
+#define	GSM_CSTATE_NULL			0
+#define	GSM_CSTATE_INITIATED		1
+#define	GSM_CSTATE_MM_CONNECTION_PEND	2 /* see 10.5.4.6 */
+#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
+
+/* Chapter 10.4.4.15 */
+struct gsm48_ra_id {
+	uint8_t digits[3];	/* MCC + MNC BCD digits */
+	uint16_t lac;		/* Location Area Code */
+	uint8_t rac;		/* Routing Area Code */
+} __attribute__ ((packed));
+
+
+
+#endif /* PROTO_GSM_04_08_H */
diff --git a/include/osmocom/gsm/protocol/gsm_04_11.h b/include/osmocom/gsm/protocol/gsm_04_11.h
new file mode 100644
index 0000000..c6a2b19
--- /dev/null
+++ b/include/osmocom/gsm/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/osmocom/gsm/protocol/gsm_04_12.h b/include/osmocom/gsm/protocol/gsm_04_12.h
new file mode 100644
index 0000000..9b1538a
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_04_12.h
@@ -0,0 +1,31 @@
+#ifndef PROTO_GSM_04_12_H
+#define PROTO_GSM_04_12_H
+
+#include <stdint.h>
+
+/* GSM TS 04.12 definitions for Short Message Service Cell Broadcast */
+
+#define GSM412_SEQ_FST_BLOCK		0x0
+#define GSM412_SEQ_SND_BLOCK		0x1
+#define GSM412_SEQ_TRD_BLOCK		0x2
+#define GSM412_SEQ_FTH_BLOCK		0x3
+#define GSM412_SEQ_FST_SCHED_BLOCK	0x8
+#define GSM412_SEQ_NULL_MSG		0xf
+
+struct gsm412_block_type {
+	uint8_t	seq_nr : 4,
+		lb : 1,
+		lpd : 2,
+		spare : 1;
+} __attribute__((packed));
+
+struct gsm412_sched_msg {
+	uint8_t beg_slot_nr : 6,
+		type : 2;
+	uint8_t end_slot_nr : 6,
+		spare1 : 1, spare2: 1;
+	uint8_t cbsms_msg_map[6];
+	uint8_t data[0];
+} __attribute__((packed));
+
+#endif
diff --git a/include/osmocom/gsm/protocol/gsm_04_80.h b/include/osmocom/gsm/protocol/gsm_04_80.h
new file mode 100644
index 0000000..fa5c945
--- /dev/null
+++ b/include/osmocom/gsm/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/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h
new file mode 100644
index 0000000..6b8f935
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_08_08.h
@@ -0,0 +1,303 @@
+/* From GSM08.08 */
+
+#ifndef GSM_0808_H
+#define GSM_0808_H
+
+#include <stdlib.h>
+
+/*
+ * this is from GSM 03.03 CGI but is copied in GSM 08.08
+ * in § 3.2.2.27 for Cell Identifier List
+ */
+enum CELL_IDENT {
+	CELL_IDENT_WHOLE_GLOBAL		= 0,
+	CELL_IDENT_LAC_AND_CI		= 1,
+	CELL_IDENT_CI			= 2,
+	CELL_IDENT_NO_CELL		= 3,
+	CELL_IDENT_LAI_AND_LAC		= 4,
+	CELL_IDENT_LAC			= 5,
+	CELL_IDENT_BSS			= 6,
+	CELL_IDENT_UTRAN_PLMN_LAC_RNC	= 8,
+	CELL_IDENT_UTRAN_RNC		= 9,
+	CELL_IDENT_UTRAN_LAC_RNC	= 10,
+};
+
+
+/* GSM 08.06 § 6.3 */
+enum BSSAP_MSG_TYPE {
+	BSSAP_MSG_BSS_MANAGEMENT    = 0x0,
+	BSSAP_MSG_DTAP		    = 0x1,
+};
+
+struct bssmap_header {
+	uint8_t type;
+	uint8_t length;
+} __attribute__((packed));
+
+struct dtap_header {
+	uint8_t type;
+	uint8_t link_id;
+	uint8_t length;
+} __attribute__((packed));
+
+
+enum BSS_MAP_MSG_TYPE {
+	BSS_MAP_MSG_RESERVED_0		= 0,
+
+	/* ASSIGNMENT MESSAGES */
+	BSS_MAP_MSG_ASSIGMENT_RQST	= 1,
+	BSS_MAP_MSG_ASSIGMENT_COMPLETE	= 2,
+	BSS_MAP_MSG_ASSIGMENT_FAILURE	= 3,
+
+	/*  HANDOVER MESSAGES */
+	BSS_MAP_MSG_HANDOVER_RQST		= 16,
+	BSS_MAP_MSG_HANDOVER_REQUIRED		= 17,
+	BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18,
+	BSS_MAP_MSG_HANDOVER_CMD		= 19,
+	BSS_MAP_MSG_HANDOVER_COMPLETE		= 20,
+	BSS_MAP_MSG_HANDOVER_SUCCEEDED		= 21,
+	BSS_MAP_MSG_HANDOVER_FAILURE		= 22,
+	BSS_MAP_MSG_HANDOVER_PERFORMED		= 23,
+	BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE	= 24,
+	BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE	= 25,
+	BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT	= 26,
+	BSS_MAP_MSG_HANDOVER_DETECT		= 27,
+
+	/* RELEASE MESSAGES */
+	BSS_MAP_MSG_CLEAR_CMD		= 32,
+	BSS_MAP_MSG_CLEAR_COMPLETE		= 33,
+	BSS_MAP_MSG_CLEAR_RQST		= 34,
+	BSS_MAP_MSG_RESERVED_1			= 35,
+	BSS_MAP_MSG_RESERVED_2			= 36,
+	BSS_MAP_MSG_SAPI_N_REJECT		= 37,
+	BSS_MAP_MSG_CONFUSION			= 38,
+
+	/* OTHER CONNECTION RELATED MESSAGES */
+	BSS_MAP_MSG_SUSPEND			= 40,
+	BSS_MAP_MSG_RESUME			= 41,
+	BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION = 42,
+	BSS_MAP_MSG_PERFORM_LOCATION_RQST	= 43,
+	BSS_MAP_MSG_LSA_INFORMATION		= 44,
+	BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE	= 45,
+	BSS_MAP_MSG_PERFORM_LOCATION_ABORT	= 46,
+	BSS_MAP_MSG_COMMON_ID			= 47,
+
+	/* GENERAL MESSAGES */
+	BSS_MAP_MSG_RESET			= 48,
+	BSS_MAP_MSG_RESET_ACKNOWLEDGE		= 49,
+	BSS_MAP_MSG_OVERLOAD			= 50,
+	BSS_MAP_MSG_RESERVED_3			= 51,
+	BSS_MAP_MSG_RESET_CIRCUIT		= 52,
+	BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE	= 53,
+	BSS_MAP_MSG_MSC_INVOKE_TRACE		= 54,
+	BSS_MAP_MSG_BSS_INVOKE_TRACE		= 55,
+	BSS_MAP_MSG_CONNECTIONLESS_INFORMATION	= 58,
+
+	/* TERRESTRIAL RESOURCE MESSAGES */
+	BSS_MAP_MSG_BLOCK			= 64,
+	BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE	= 65,
+	BSS_MAP_MSG_UNBLOCK			= 66,
+	BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE	= 67,
+	BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK		= 68,
+	BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE	= 69,
+	BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK	= 70,
+	BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE = 71,
+	BSS_MAP_MSG_UNEQUIPPED_CIRCUIT		= 72,
+	BSS_MAP_MSG_CHANGE_CIRCUIT		= 78,
+	BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE	= 79,
+
+	/* RADIO RESOURCE MESSAGES */
+	BSS_MAP_MSG_RESOURCE_RQST		= 80,
+	BSS_MAP_MSG_RESOURCE_INDICATION		= 81,
+	BSS_MAP_MSG_PAGING			= 82,
+	BSS_MAP_MSG_CIPHER_MODE_CMD		= 83,
+	BSS_MAP_MSG_CLASSMARK_UPDATE		= 84,
+	BSS_MAP_MSG_CIPHER_MODE_COMPLETE	= 85,
+	BSS_MAP_MSG_QUEUING_INDICATION		= 86,
+	BSS_MAP_MSG_COMPLETE_LAYER_3		= 87,
+	BSS_MAP_MSG_CLASSMARK_RQST		= 88,
+	BSS_MAP_MSG_CIPHER_MODE_REJECT		= 89,
+	BSS_MAP_MSG_LOAD_INDICATION		= 90,
+
+	/* VGCS/VBS */
+	BSS_MAP_MSG_VGCS_VBS_SETUP		= 4,
+	BSS_MAP_MSG_VGCS_VBS_SETUP_ACK		= 5,
+	BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE	= 6,
+	BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST	= 7,
+	BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT	= 28,
+	BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE	= 29,
+	BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION	= 30,
+	BSS_MAP_MSG_UPLINK_RQST		= 31,
+	BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE	= 39,
+	BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION	= 73,
+	BSS_MAP_MSG_UPLINK_RELEASE_INDICATION	= 74,
+	BSS_MAP_MSG_UPLINK_REJECT_CMD	= 75,
+	BSS_MAP_MSG_UPLINK_RELEASE_CMD	= 76,
+	BSS_MAP_MSG_UPLINK_SEIZED_CMD	= 77,
+};
+
+enum GSM0808_IE_CODING {
+	GSM0808_IE_CIRCUIT_IDENTITY_CODE	= 1,
+	GSM0808_IE_RESERVED_0			= 2,
+	GSM0808_IE_RESOURCE_AVAILABLE		= 3,
+	GSM0808_IE_CAUSE			= 4,
+	GSM0808_IE_CELL_IDENTIFIER		= 5,
+	GSM0808_IE_PRIORITY			= 6,
+	GSM0808_IE_LAYER_3_HEADER_INFORMATION	= 7,
+	GSM0808_IE_IMSI				= 8,
+	GSM0808_IE_TMSI				= 9,
+	GSM0808_IE_ENCRYPTION_INFORMATION	= 10,
+	GSM0808_IE_CHANNEL_TYPE			= 11,
+	GSM0808_IE_PERIODICITY			= 12,
+	GSM0808_IE_EXTENDED_RESOURCE_INDICATOR	= 13,
+	GSM0808_IE_NUMBER_OF_MSS		= 14,
+	GSM0808_IE_RESERVED_1			= 15,
+	GSM0808_IE_RESERVED_2			= 16,
+	GSM0808_IE_RESERVED_3			= 17,
+	GSM0808_IE_CLASSMARK_INFORMATION_T2	= 18,
+	GSM0808_IE_CLASSMARK_INFORMATION_T3	= 19,
+	GSM0808_IE_INTERFERENCE_BAND_TO_USE	= 20,
+	GSM0808_IE_RR_CAUSE			= 21,
+	GSM0808_IE_RESERVED_4			= 22,
+	GSM0808_IE_LAYER_3_INFORMATION		= 23,
+	GSM0808_IE_DLCI				= 24,
+	GSM0808_IE_DOWNLINK_DTX_FLAG		= 25,
+	GSM0808_IE_CELL_IDENTIFIER_LIST		= 26,
+	GSM0808_IE_RESPONSE_RQST		= 27,
+	GSM0808_IE_RESOURCE_INDICATION_METHOD	= 28,
+	GSM0808_IE_CLASSMARK_INFORMATION_TYPE_1	= 29,
+	GSM0808_IE_CIRCUIT_IDENTITY_CODE_LIST	= 30,
+	GSM0808_IE_DIAGNOSTIC			= 31,
+	GSM0808_IE_LAYER_3_MESSAGE_CONTENTS	= 32,
+	GSM0808_IE_CHOSEN_CHANNEL		= 33,
+	GSM0808_IE_TOTAL_RESOURCE_ACCESSIBLE	= 34,
+	GSM0808_IE_CIPHER_RESPONSE_MODE		= 35,
+	GSM0808_IE_CHANNEL_NEEDED		= 36,
+	GSM0808_IE_TRACE_TYPE			= 37,
+	GSM0808_IE_TRIGGERID			= 38,
+	GSM0808_IE_TRACE_REFERENCE		= 39,
+	GSM0808_IE_TRANSACTIONID		= 40,
+	GSM0808_IE_MOBILE_IDENTITY		= 41,
+	GSM0808_IE_OMCID			= 42,
+	GSM0808_IE_FORWARD_INDICATOR		= 43,
+	GSM0808_IE_CHOSEN_ENCR_ALG		= 44,
+	GSM0808_IE_CIRCUIT_POOL			= 45,
+	GSM0808_IE_CIRCUIT_POOL_LIST		= 46,
+	GSM0808_IE_TIME_INDICATION		= 47,
+	GSM0808_IE_RESOURCE_SITUATION		= 48,
+	GSM0808_IE_CURRENT_CHANNEL_TYPE_1	= 49,
+	GSM0808_IE_QUEUEING_INDICATOR		= 50,
+	GSM0808_IE_SPEECH_VERSION		= 64,
+	GSM0808_IE_ASSIGNMENT_REQUIREMENT	= 51,
+	GSM0808_IE_TALKER_FLAG			= 53,
+	GSM0808_IE_CONNECTION_RELEASE_RQSTED	= 54,
+	GSM0808_IE_GROUP_CALL_REFERENCE		= 55,
+	GSM0808_IE_EMLPP_PRIORITY		= 56,
+	GSM0808_IE_CONFIG_EVO_INDI		= 57,
+	GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION	= 58,
+	GSM0808_IE_LSA_IDENTIFIER		= 59,
+	GSM0808_IE_LSA_IDENTIFIER_LIST		= 60,
+	GSM0808_IE_LSA_INFORMATION		= 61,
+	GSM0808_IE_LCS_QOS			= 62,
+	GSM0808_IE_LSA_ACCESS_CTRL_SUPPR	= 63,
+	GSM0808_IE_LCS_PRIORITY			= 67,
+	GSM0808_IE_LOCATION_TYPE		= 68,
+	GSM0808_IE_LOCATION_ESTIMATE		= 69,
+	GSM0808_IE_POSITIONING_DATA		= 70,
+	GSM0808_IE_LCS_CAUSE			= 71,
+	GSM0808_IE_LCS_CLIENT_TYPE		= 72,
+	GSM0808_IE_APDU				= 73,
+	GSM0808_IE_NETWORK_ELEMENT_IDENTITY	= 74,
+	GSM0808_IE_GPS_ASSISTANCE_DATA		= 75,
+	GSM0808_IE_DECIPHERING_KEYS		= 76,
+	GSM0808_IE_RETURN_ERROR_RQST		= 77,
+	GSM0808_IE_RETURN_ERROR_CAUSE		= 78,
+	GSM0808_IE_SEGMENTATION			= 79,
+	GSM0808_IE_SERVICE_HANDOVER		= 80,
+	GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS	= 81,
+	GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82,
+	GSM0808_IE_RESERVED_5			= 65,
+	GSM0808_IE_RESERVED_6			= 66,
+};
+
+enum gsm0808_cause {
+	GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE			= 0,
+	GSM0808_CAUSE_RADIO_INTERFACE_FAILURE				= 1,
+	GSM0808_CAUSE_UPLINK_QUALITY					= 2,
+	GSM0808_CAUSE_UPLINK_STRENGTH					= 3,
+	GSM0808_CAUSE_DOWNLINK_QUALITY					= 4,
+	GSM0808_CAUSE_DOWNLINK_STRENGTH					= 5,
+	GSM0808_CAUSE_DISTANCE						= 6,
+	GSM0808_CAUSE_O_AND_M_INTERVENTION				= 7,
+	GSM0808_CAUSE_RESPONSE_TO_MSC_INVOCATION			= 8,
+	GSM0808_CAUSE_CALL_CONTROL					= 9,
+	GSM0808_CAUSE_RADIO_INTERFACE_FAILURE_REVERSION			= 10,
+	GSM0808_CAUSE_HANDOVER_SUCCESSFUL				= 11,
+	GSM0808_CAUSE_BETTER_CELL					= 12,
+	GSM0808_CAUSE_DIRECTED_RETRY					= 13,
+	GSM0808_CAUSE_JOINED_GROUP_CALL_CHANNEL				= 14,
+	GSM0808_CAUSE_TRAFFIC						= 15,
+	GSM0808_CAUSE_EQUIPMENT_FAILURE					= 32,
+	GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE			= 33,
+	GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE	= 34,
+	GSM0808_CAUSE_CCCH_OVERLOAD					= 35,
+	GSM0808_CAUSE_PROCESSOR_OVERLOAD				= 36,
+	GSM0808_CAUSE_BSS_NOT_EQUIPPED					= 37,
+	GSM0808_CAUSE_MS_NOT_EQUIPPED					= 38,
+	GSM0808_CAUSE_INVALID_CELL					= 39,
+	GSM0808_CAUSE_TRAFFIC_LOAD					= 40,
+	GSM0808_CAUSE_PREEMPTION					= 41,
+	GSM0808_CAUSE_RQSTED_TRANSCODING_RATE_ADAPTION_UNAVAILABLE	= 48,
+	GSM0808_CAUSE_CIRCUIT_POOL_MISMATCH				= 49,
+	GSM0808_CAUSE_SWITCH_CIRCUIT_POOL				= 50,
+	GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE		= 51,
+	GSM0808_CAUSE_LSA_NOT_ALLOWED					= 52,
+	GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED			= 64,
+	GSM0808_CAUSE_TERRESTRIAL_CIRCUIT_ALREADY_ALLOCATED		= 80,
+	GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS				= 81,
+	GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING		= 82,
+	GSM0808_CAUSE_INCORRECT_VALUE					= 83,
+	GSM0808_CAUSE_UNKNOWN_MESSAGE_TYPE				= 84,
+	GSM0808_CAUSE_UNKNOWN_INFORMATION_ELEMENT			= 85,
+	GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC		= 96,
+};
+
+/* GSM 08.08 3.2.2.11 Channel Type */
+enum gsm0808_chan_indicator {
+	GSM0808_CHAN_SPEECH = 1,
+	GSM0808_CHAN_DATA   = 2,
+	GSM0808_CHAN_SIGN   = 3,
+};
+
+enum gsm0808_chan_rate_type_data {
+	GSM0808_DATA_FULL_BM	= 0x8,
+	GSM0808_DATA_HALF_LM	= 0x9,
+	GSM0808_DATA_FULL_RPREF	= 0xa,
+	GSM0808_DATA_HALF_PREF	= 0xb,
+	GSM0808_DATA_FULL_PREF_NO_CHANGE	= 0x1a,
+	GSM0808_DATA_HALF_PREF_NO_CHANGE	= 0x1b,
+	GSM0808_DATA_MULTI_MASK	= 0x20,
+	GSM0808_DATA_MULTI_MASK_NO_CHANGE	= 0x30,
+};
+
+enum gsm0808_chan_rate_type_speech {
+	GSM0808_SPEECH_FULL_BM	= 0x8,
+	GSM0808_SPEECH_HALF_LM	= 0x9,
+	GSM0808_SPEECH_FULL_PREF= 0xa,
+	GSM0808_SPEECH_HALF_PREF= 0xb,
+	GSM0808_SPEECH_FULL_PREF_NO_CHANGE	= 0x1a,
+	GSM0808_SPEECH_HALF_PREF_NO_CHANGE	= 0x1b,
+	GSM0808_SPEECH_PERM	= 0xf,
+	GSM0808_SPEECH_PERM_NO_CHANGE = 0x1f,
+};
+
+enum gsm0808_permitted_speech {
+	GSM0808_PERM_FR1	= 0x01,
+	GSM0808_PERM_FR2	= 0x11,
+	GSM0808_PERM_FR3	= 0x21,
+	GSM0808_PERM_HR1	= GSM0808_PERM_FR1 | 0x4,
+	GSM0808_PERM_HR2	= GSM0808_PERM_FR2 | 0x4,
+	GSM0808_PERM_HR3	= GSM0808_PERM_FR3 | 0x4,
+};
+
+#endif
diff --git a/include/osmocom/gsm/protocol/gsm_08_58.h b/include/osmocom/gsm/protocol/gsm_08_58.h
new file mode 100644
index 0000000..74a4083
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_08_58.h
@@ -0,0 +1,546 @@
+#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 8.5 */
+struct abis_rsl_cchan_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 */
+	RSL_MT_SUSP_REQ,		/* non-standard elements */
+	RSL_MT_SUSP_CONF,
+	RSL_MT_RES_REQ,
+	RSL_MT_RECON_REQ,		/* 0x0f */
+
+	/* 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,
+	RSL_MT_CHAN_CONF,		/* non-standard element */
+	/* 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 9.3.45 */
+struct rsl_ie_cb_cmd_type {
+	uint8_t last_block:2;
+	uint8_t spare:1;
+	uint8_t def_bcast:1;
+	uint8_t command:4;
+} __attribute__ ((packed));
+/* ->command */
+#define RSL_CB_CMD_TYPE_NORMAL		0x00
+#define RSL_CB_CMD_TYPE_SCHEDULE	0x08
+#define RSL_CB_CMD_TYPE_DEFAULT		0x0e
+#define RSL_CB_CMD_TYPE_NULL		0x0f
+/* ->def_bcast */
+#define RSL_CB_CMD_DEFBCAST_NORMAL	0
+#define RSL_CB_CMD_DEFBCAST_NULL	1
+/* ->last_block */
+#define RSL_CB_CMD_LASTBLOCK_4		0
+#define RSL_CB_CMD_LASTBLOCK_1		1
+#define RSL_CB_CMD_LASTBLOCK_2		2
+#define RSL_CB_CMD_LASTBLOCK_3		3
+
+/* 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/osmocom/gsm/protocol/gsm_12_21.h b/include/osmocom/gsm/protocol/gsm_12_21.h
new file mode 100644
index 0000000..b8b00f3
--- /dev/null
+++ b/include/osmocom/gsm/protocol/gsm_12_21.h
@@ -0,0 +1,713 @@
+#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 <osmocom/gsm/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,
+	NM_IPAC_EIE_CONFIG		= 0x07,
+	NM_IPAC_EIE_RES_DETAILS		= 0x08,
+	NM_IPAC_EIE_RXLEV_THRESH	= 0x09,
+	NM_IPAC_EIE_FREQ_SYNC_OPTS	= 0x0a,
+	NM_IPAC_EIE_MAC_ADDR		= 0x0b,
+	NM_IPAC_EIE_HW_SW_COMPAT_NR	= 0x0c,
+	NM_IPAC_EIE_MANUF_SER_NR	= 0x0d,
+	NM_IPAC_EIE_OEM_ID		= 0x0e,
+	NM_IPAC_EIE_DATE_TIME_MANUF	= 0x0f,
+	NM_IPAC_EIE_DATE_TIME_CALIB	= 0x10,
+	NM_IPAC_EIE_BEACON_INFO		= 0x11,
+	NM_IPAC_EIE_FREQ_ERR		= 0x12,
+	/* FIXME */
+	NM_IPAC_EIE_FREQ_BANDS		= 0x1c,
+	NM_IPAC_EIE_MAX_TA		= 0x1d,
+	NM_IPAC_EIE_CIPH_ALGOS		= 0x1e,
+	NM_IPAC_EIE_CHAN_TYPES		= 0x1f,
+	NM_IPAC_EIE_CHAN_MODES		= 0x20,
+	NM_IPAC_EIE_GPRS_CODING		= 0x21,
+	NM_IPAC_EIE_RTP_FEATURES	= 0x22,
+	NM_IPAC_EIE_RSL_FEATURES	= 0x23,
+	NM_IPAC_EIE_BTS_HW_CLASS	= 0x24,
+	NM_IPAC_EIE_BTS_ID		= 0x25,
+};
+
+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/osmocom/gsm/rsl.h b/include/osmocom/gsm/rsl.h
new file mode 100644
index 0000000..7e46330
--- /dev/null
+++ b/include/osmocom/gsm/rsl.h
@@ -0,0 +1,41 @@
+#ifndef _OSMOCORE_RSL_H
+#define _OSMOCORE_RSL_H
+
+#include <stdint.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+
+void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type);
+
+void rsl_init_cchan_hdr(struct abis_rsl_cchan_hdr *ch, uint8_t msg_type);
+
+extern const struct tlv_definition rsl_att_tlvdef;
+#define rsl_tlv_parse(dec, buf, len)     \
+			tlv_parse(dec, &rsl_att_tlvdef, buf, len, 0, 0)
+
+/* encode channel number as per Section 9.3.1 */
+uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot);
+/* decode channel number as per Section 9.3.1 */
+int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot);
+/* Turns channel number into a string */
+const char *rsl_chan_nr_str(uint8_t chan_nr);
+
+
+const char *rsl_err_name(uint8_t err);
+const char *rsl_rlm_cause_name(uint8_t err);
+
+/* Section 3.3.2.3 TS 05.02. I think this looks like a table */
+int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
+
+/* Push a RSL RLL header */
+void rsl_rll_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr,
+		      uint8_t link_id, int transparent);
+
+/* Push a RSL RLL header with L3_INFO IE */
+void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr,
+		     uint8_t link_id, int transparent);
+
+/* Allocate msgb and fill with simple RSL RLL header */
+struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr,
+			    uint8_t link_id, int transparent);
+#endif /* _OSMOCORE_RSL_H */
diff --git a/include/osmocom/gsm/rxlev_stat.h b/include/osmocom/gsm/rxlev_stat.h
new file mode 100644
index 0000000..415509d
--- /dev/null
+++ b/include/osmocom/gsm/rxlev_stat.h
@@ -0,0 +1,22 @@
+#ifndef _OSMOCORE_RXLEV_STATS_H
+#define _OSMOCORE_RXLEV_STATS_H
+
+#define NUM_RXLEVS 32
+#define NUM_ARFCNS 1024
+
+struct rxlev_stats {
+	/* the maximum number of ARFCN's is 1024, and there are 32 RxLevels,
+	 * so in we keep one 1024bit-bitvec for each RxLev */
+	uint8_t rxlev_buckets[NUM_RXLEVS][NUM_ARFCNS/8];
+};
+
+void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev);
+
+/* get the next ARFCN that has the specified Rxlev */
+int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn);
+
+void rxlev_stat_reset(struct rxlev_stats *st);
+
+void rxlev_stat_dump(const struct rxlev_stats *st);
+
+#endif /* _OSMOCORE_RXLEV_STATS_H */
diff --git a/include/osmocom/gsm/tlv.h b/include/osmocom/gsm/tlv.h
new file mode 100644
index 0000000..552af2b
--- /dev/null
+++ b/include/osmocom/gsm/tlv.h
@@ -0,0 +1,260 @@
+#ifndef _TLV_H
+#define _TLV_H
+
+#include <stdint.h>
+#include <string.h>
+
+#include <osmocom/core/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;
+}
+
+static inline uint8_t *tv_fixed_put(uint8_t *buf, uint8_t tag,
+				    unsigned int len, const uint8_t *val)
+{
+	*buf++ = tag;
+	memcpy(buf, val, len);
+	return buf + len;
+}
+
+/* '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_tv_fixed_put(struct msgb *msg, uint8_t tag,
+					unsigned int len, const uint8_t *val)
+{
+	uint8_t *buf = msgb_put(msg, 1+len);
+	return tv_fixed_put(buf, tag, len, 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);
+}
+
+static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len,
+				      const uint8_t *val)
+{
+	uint8_t *buf = msgb_push(msg, TVLV_GROSS_LEN(len));
+	return tvlv_put(buf, tag, len, 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,
+	TLV_TYPE_SINGLE_TV
+};
+
+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/osmocom/vty/telnet_interface.h b/include/osmocom/vty/telnet_interface.h
index 444e649..0c034e4 100644
--- a/include/osmocom/vty/telnet_interface.h
+++ b/include/osmocom/vty/telnet_interface.h
@@ -21,8 +21,8 @@
 #ifndef TELNET_INTERFACE_H
 #define TELNET_INTERFACE_H
 
-#include <osmocore/logging.h>
-#include <osmocore/select.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/select.h>
 
 #include <osmocom/vty/vty.h>