aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/core
diff options
context:
space:
mode:
Diffstat (limited to 'include/osmocom/core')
-rw-r--r--include/osmocom/core/Makefile.am12
-rw-r--r--include/osmocom/core/backtrace.h6
-rw-r--r--include/osmocom/core/bits.h45
-rw-r--r--include/osmocom/core/bitvec.h75
-rw-r--r--include/osmocom/core/crc16.h34
-rw-r--r--include/osmocom/core/gsmtap.h89
-rw-r--r--include/osmocom/core/gsmtap_util.h21
-rw-r--r--include/osmocom/core/linuxlist.h360
-rw-r--r--include/osmocom/core/logging.h154
-rw-r--r--include/osmocom/core/msgb.h197
-rw-r--r--include/osmocom/core/msgfile.h49
-rw-r--r--include/osmocom/core/panic.h11
-rw-r--r--include/osmocom/core/plugin.h6
-rw-r--r--include/osmocom/core/process.h6
-rw-r--r--include/osmocom/core/rate_ctr.h81
-rw-r--r--include/osmocom/core/select.h22
-rw-r--r--include/osmocom/core/signal.h15
-rw-r--r--include/osmocom/core/statistics.h31
-rw-r--r--include/osmocom/core/talloc.h192
-rw-r--r--include/osmocom/core/timer.h72
-rw-r--r--include/osmocom/core/utils.h30
-rw-r--r--include/osmocom/core/write_queue.h46
22 files changed, 1554 insertions, 0 deletions
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