Merge commit 'ba01fa44feb6deb0f0359f381eafe866991c06c1' into pablo/namespace
authorPablo Neira Ayuso <pablo@gnumonks.org>
Sun, 15 May 2011 12:39:08 +0000 (14:39 +0200)
committerPablo Neira Ayuso <pablo@gnumonks.org>
Sun, 15 May 2011 12:39:08 +0000 (14:39 +0200)
48 files changed:
1  2 
src/shared/libosmocore/debian/changelog
src/shared/libosmocore/debian/libosmocore-dev.dirs
src/shared/libosmocore/debian/libosmocore.dirs
src/shared/libosmocore/include/osmocom/core/Makefile.am
src/shared/libosmocore/include/osmocom/core/application.h
src/shared/libosmocore/include/osmocom/core/backtrace.h
src/shared/libosmocore/include/osmocom/core/conv.h
src/shared/libosmocore/include/osmocom/core/crc16.h
src/shared/libosmocore/include/osmocom/core/gsmtap_util.h
src/shared/libosmocore/include/osmocom/core/msgb.h
src/shared/libosmocore/include/osmocom/core/msgfile.h
src/shared/libosmocore/include/osmocom/core/panic.h
src/shared/libosmocore/include/osmocom/core/plugin.h
src/shared/libosmocore/include/osmocom/core/select.h
src/shared/libosmocore/include/osmocom/core/signal.h
src/shared/libosmocore/include/osmocom/core/statistics.h
src/shared/libosmocore/include/osmocom/core/timer.h
src/shared/libosmocore/include/osmocom/core/utils.h
src/shared/libosmocore/include/osmocom/core/write_queue.h
src/shared/libosmocore/include/osmocom/gsm/Makefile.am
src/shared/libosmocore/include/osmocom/gsm/a5.h
src/shared/libosmocore/include/osmocom/vty/telnet_interface.h
src/shared/libosmocore/src/Makefile.am
src/shared/libosmocore/src/application.c
src/shared/libosmocore/src/backtrace.c
src/shared/libosmocore/src/codec/Makefile.am
src/shared/libosmocore/src/conv.c
src/shared/libosmocore/src/crc16.c
src/shared/libosmocore/src/gsm/Makefile.am
src/shared/libosmocore/src/gsm/a5.c
src/shared/libosmocore/src/gsm/gprs_cipher_core.c
src/shared/libosmocore/src/gsm/gsm48.c
src/shared/libosmocore/src/gsmtap_util.c
src/shared/libosmocore/src/logging.c
src/shared/libosmocore/src/msgfile.c
src/shared/libosmocore/src/panic.c
src/shared/libosmocore/src/plugin.c
src/shared/libosmocore/src/rate_ctr.c
src/shared/libosmocore/src/select.c
src/shared/libosmocore/src/signal.c
src/shared/libosmocore/src/statistics.c
src/shared/libosmocore/src/timer.c
src/shared/libosmocore/src/utils.c
src/shared/libosmocore/src/vty/Makefile.am
src/shared/libosmocore/src/vty/telnet_interface.c
src/shared/libosmocore/src/write_queue.c
src/shared/libosmocore/tests/msgfile/msgfile_test.c
src/shared/libosmocore/tests/timer/timer_test.c

index 4c103cb,0000000..20a0493
mode 100644,000000..100644
--- /dev/null
@@@ -1,11 -1,0 +1,17 @@@
++libosmocore (0.3.0) natty; urgency=low
++
++  * New upstream version of libosmocore
++
++ -- Harald Welte <laforge@gnumonks.org>  Tue, 10 May 2011 17:28:24 +0200
++
 +libosmocore (0.1.27) natty; urgency=low
 +
 +  * New upstream version of libosmocore.
 +
 + -- Holger Hans Peter Freyther <holger@freyther.de>  Thu, 13 Jan 2011 18:07:36 +0800
 +
 +libosmocore (0.1.17-1) unstable; urgency=low
 +
 +  * Initial release (Closes: #nnnn)  <nnnn is the bug number of your ITP>
 +
 + -- Harald Welte <laforge@gnumonks.org>  Tue, 24 Aug 2010 10:55:04 +0200
index e168dc6,0000000..94090a3
mode 100644,000000..100644
--- /dev/null
@@@ -1,5 -1,0 +1,8 @@@
- usr/include/osmocore
 +usr/lib
 +usr/include
 +usr/include/osmocom
++usr/include/osmocom/codec
++usr/include/osmocom/core
++usr/include/osmocom/crypt
++usr/include/osmocom/gsm
 +usr/include/osmocom/vty
index e168dc6,0000000..94090a3
mode 100644,000000..100644
--- /dev/null
@@@ -1,5 -1,0 +1,8 @@@
- usr/include/osmocore
 +usr/lib
 +usr/include
 +usr/include/osmocom
++usr/include/osmocom/codec
++usr/include/osmocom/core
++usr/include/osmocom/crypt
++usr/include/osmocom/gsm
 +usr/include/osmocom/vty
index 6109f47,0000000..3698873
mode 100644,000000..100644
--- /dev/null
@@@ -1,12 -1,0 +1,12 @@@
-                  backtrace.h
 +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 conv.h application.h
 +
 +if ENABLE_TALLOC
 +osmocore_HEADERS += talloc.h
 +endif
 +
 +osmocoredir = $(includedir)/osmocom/core
index 0000000,0000000..c1642ec
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++#ifndef OSMO_APPLICATION_H
++#define OSMO_APPLICATION_H
++
++/**
++ * Routines for helping with the application setup.
++ */
++
++struct log_info;
++struct log_target;
++
++extern struct log_target *osmo_stderr_target;
++
++void osmo_init_ignore_signals(void);
++int osmo_init_logging(const struct log_info *);
++
++#endif
index bbbb2c2,0000000..5a8a816
mode 100644,000000..100644
--- /dev/null
@@@ -1,6 -1,0 +1,6 @@@
- void generate_backtrace();
 +#ifndef _OSMO_BACKTRACE_H_
 +#define _OSMO_BACKTRACE_H_
 +
++void osmo_generate_backtrace();
 +
 +#endif
index 0000000,0000000..af676ee
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,101 @@@
++/*
++ * conv.h
++ *
++ * Copyright (C) 2011  Sylvain Munaut <tnt@246tNt.com>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#ifndef __OSMO_CONV_H__
++#define __OSMO_CONV_H__
++
++#include <stdint.h>
++
++#include <osmocom/core/bits.h>
++
++struct osmo_conv_code {
++      int N;
++      int K;
++      int len;
++
++      const uint8_t (*next_output)[2];
++      const uint8_t (*next_state)[2];
++
++      const uint8_t *next_term_output;
++      const uint8_t *next_term_state;
++
++      const int *puncture;
++};
++
++
++/* Encoding */
++
++      /* Low level API */
++struct osmo_conv_encoder {
++      const struct osmo_conv_code *code;
++      int i_idx;      /* Next input bit index */
++      int p_idx;      /* Current puncture index */
++      uint8_t state;  /* Current state */
++};
++
++void osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
++                           const struct osmo_conv_code *code);
++int  osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
++                          const ubit_t *input, ubit_t *output, int n);
++int  osmo_conv_encode_finish(struct osmo_conv_encoder *encoder, ubit_t *output);
++
++      /* All-in-one */
++int  osmo_conv_encode(const struct osmo_conv_code *code,
++                      const ubit_t *input, ubit_t *output);
++
++
++/* Decoding */
++
++      /* Low level API */
++struct osmo_conv_decoder {
++      const struct osmo_conv_code *code;
++
++      int n_states;
++
++      int len;                /* Max o_idx (excl. termination) */
++
++      int o_idx;              /* output index */
++      int p_idx;              /* puncture index */
++
++      unsigned int *ae;       /* accumulater error */
++      unsigned int *ae_next;  /* next accumulated error (tmp in scan) */
++      uint8_t *state_history; /* state history [len][n_states] */
++};
++
++void osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
++                           const struct osmo_conv_code *code, int len);
++void osmo_conv_decode_reset(struct osmo_conv_decoder *decoder);
++void osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder);
++
++int osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
++                          const sbit_t *input, int n);
++int osmo_conv_decode_finish(struct osmo_conv_decoder *decoder,
++                            const sbit_t *input);
++int osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
++                                ubit_t *output, int has_finish);
++
++      /* All-in-one */
++int osmo_conv_decode(const struct osmo_conv_code *code,
++                     const sbit_t *input, ubit_t *output);
++
++
++#endif /* __OSMO_CONV_H__ */
index 7a51249,0000000..0e52417
mode 100644,000000..100644
--- /dev/null
@@@ -1,34 -1,0 +1,34 @@@
- extern uint16_t const crc16_table[256];
 +/*
 + * 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 crc16(uint16_t crc, const uint8_t *buffer, size_t len);
++extern uint16_t const osmo_crc16_table[256];
 +
- static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data)
++extern uint16_t osmo_crc16(uint16_t crc, const uint8_t *buffer, size_t len);
 +
-       return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
++static inline uint16_t osmo_crc16_byte(uint16_t crc, const uint8_t data)
 +{
++      return (crc >> 8) ^ osmo_crc16_table[(crc ^ data) & 0xff];
 +}
 +
 +#endif /* __CRC16_H */
index 9644944,0000000..785f5e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,21 -1,0 +1,25 @@@
 +#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);
 +
++/* Create a local 'gsmtap sink' avoiding the UDP packets being rejected
++ * with ICMP reject messages */
++int gsmtap_sink_init(uint32_t bind_ip);
++
 +#endif /* _GSMTAP_UTIL_H */
index 57b5d7f,0000000..8665c2b
mode 100644,000000..100644
--- /dev/null
@@@ -1,197 -1,0 +1,197 @@@
-       static_assert(size > headroom, headroom_bigger);
 +#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)
 +{
++      osmo_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 */
index 92caa9f,0000000..c5e67a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,49 -1,0 +1,49 @@@
- #include "linuxlist.h"
 +/*
 + * (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
 +
- struct msg_entry {
++#include <osmocom/core/linuxlist.h>
 +
 +/**
 + * One message in the list.
 + */
- struct msg_entries {
++struct osmo_config_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 *msg_entry_parse(void *ctx, const char *filename);
++struct osmo_config_list {
 +      struct llist_head entry;
 +};
 +
++struct osmo_config_list* osmo_config_list_parse(void *ctx, const char *filename);
 +
 +#endif
index c5a8377,0000000..c28a844
mode 100644,000000..100644
--- /dev/null
@@@ -1,11 -1,0 +1,11 @@@
- void osmo_panic(const char *fmt, ...);
- void osmo_set_panic_handler(osmo_panic_handler_t h);
 +#ifndef OSMOCORE_PANIC_H
 +#define OSMOCORE_PANIC_H
 +
 +#include <stdarg.h>
 +
 +typedef void (*osmo_panic_handler_t)(const char *fmt, va_list args);
 +
++extern void osmo_panic(const char *fmt, ...);
++extern void osmo_set_panic_handler(osmo_panic_handler_t h);
 +
 +#endif
index 98f9b56,0000000..6c0eccc
mode 100644,000000..100644
--- /dev/null
@@@ -1,6 -1,0 +1,6 @@@
- int plugin_load_all(const char *directory);
 +#ifndef _OSMO_PLUGIN_H
 +#define _OSMO_PLUGIN_H
 +
++int osmo_plugin_load_all(const char *directory);
 +
 +#endif
index 5ca21c3,0000000..476c564
mode 100644,000000..100644
--- /dev/null
@@@ -1,22 -1,0 +1,22 @@@
- struct bsc_fd {
 +#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
 +
-       int (*cb)(struct bsc_fd *fd, unsigned int what);
++struct osmo_fd {
 +      struct llist_head list;
 +      int fd;
 +      unsigned int when;
- int bsc_register_fd(struct bsc_fd *fd);
- void bsc_unregister_fd(struct bsc_fd *fd);
- int bsc_select_main(int polling);
++      int (*cb)(struct osmo_fd *fd, unsigned int what);
 +      void *data;
 +      unsigned int priv_nr;
 +};
 +
++int osmo_fd_register(struct osmo_fd *fd);
++void osmo_fd_unregister(struct osmo_fd *fd);
++int osmo_select_main(int polling);
 +#endif /* _BSC_SELECT_H */
index 02d83d2,0000000..535fd18
mode 100644,000000..100644
--- /dev/null
@@@ -1,15 -1,0 +1,14 @@@
- #ifndef OSMOCORE_SIGNAL_H
- #define OSMOCORE_SIGNAL_H
++#ifndef OSMO_SIGNAL_H
++#define OSMO_SIGNAL_H
 +
- typedef int signal_cbfn(unsigned int subsys, unsigned int signal,
-                       void *handler_data, void *signal_data);
++typedef int osmo_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);
++int osmo_signal_register_handler(unsigned int subsys, osmo_signal_cbfn *cbfn, void *data);
++void osmo_signal_unregister_handler(unsigned int subsys, osmo_signal_cbfn *cbfn, void *data);
 +
 +/* Dispatch */
- void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data);
++void osmo_signal_dispatch(unsigned int subsys, unsigned int signal, void *signal_data);
 +
- #endif /* OSMOCORE_SIGNAL_H */
++#endif /* OSMO_SIGNAL_H */
index 2c15965,0000000..1849327
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,33 @@@
- struct counter {
 +#ifndef _STATISTICS_H
 +#define _STATISTICS_H
 +
- static inline void counter_inc(struct counter *ctr)
++struct osmo_counter {
 +      struct llist_head list;
 +      const char *name;
 +      const char *description;
 +      unsigned long value;
 +};
 +
- static inline unsigned long counter_get(struct counter *ctr)
++static inline void osmo_counter_inc(struct osmo_counter *ctr)
 +{
 +      ctr->value++;
 +}
 +
- static inline void counter_reset(struct counter *ctr)
++static inline unsigned long osmo_counter_get(struct osmo_counter *ctr)
 +{
 +      return ctr->value;
 +}
 +
- struct counter *counter_alloc(const char *name);
- void counter_free(struct counter *ctr);
++static inline void osmo_counter_reset(struct osmo_counter *ctr)
 +{
 +      ctr->value = 0;
 +}
 +
- int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data);
++struct osmo_counter *osmo_counter_alloc(const char *name);
++void osmo_counter_free(struct osmo_counter *ctr);
 +
- struct counter *counter_get_by_name(const char *name);
++int osmo_counters_for_each(int (*handle_counter)(struct osmo_counter *, void *), void *data);
 +
++struct osmo_counter *osmo_counter_get_by_name(const char *name);
 +
 +#endif /* _STATISTICS_H */
index 1966478,0000000..db2ecbf
mode 100644,000000..100644
--- /dev/null
@@@ -1,72 -1,0 +1,72 @@@
-  *      - Create a struct timer_list
 +/*
 + * (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:
- struct timer_list {
++ *      - Create a struct osmo_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.
 + *
 + */
- 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);
++struct osmo_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
 + */
- struct timeval *bsc_nearest_timer();
- void bsc_prepare_timers();
- int bsc_update_timers();
- int bsc_timer_check(void);
++void osmo_timer_add(struct osmo_timer_list *timer);
++void osmo_timer_schedule(struct osmo_timer_list *timer, int seconds, int microseconds);
++void osmo_timer_del(struct osmo_timer_list *timer);
++int osmo_timer_pending(struct osmo_timer_list *timer);
 +
 +
 +/**
 + * internal timer list management
 + */
++struct timeval *osmo_timers_nearest();
++void osmo_timers_prepare();
++int osmo_timers_update();
++int osmo_timers_check(void);
 +
 +#endif
index 252228d,0000000..0f1ea3b
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,39 @@@
- char bcd2char(uint8_t bcd);
 +#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);
 +
- uint8_t char2bcd(char c);
++char osmo_bcd2char(uint8_t bcd);
 +/* only works for numbers in ascci */
- 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);
++uint8_t osmo_char2bcd(char c);
 +
- #define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1];
++int osmo_hexparse(const char *str, uint8_t *b, int max_len);
++char *osmo_hexdump(const unsigned char *buf, int len);
++char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len);
++char *osmo_ubit_dump(const uint8_t *bits, unsigned int len);
 +
++#define osmo_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);
 +
 +#define OSMO_SNPRINTF_RET(ret, rem, offset, len)              \
 +do {                                                          \
 +      len += ret;                                             \
 +      if (ret > rem)                                          \
 +              ret = rem;                                      \
 +      offset += ret;                                          \
 +      rem -= ret;                                             \
 +} while (0)
 +
 +#endif
index 3b730c7,0000000..41748d7
mode 100644,000000..100644
--- /dev/null
@@@ -1,46 -1,0 +1,46 @@@
- #ifndef write_queue_h
- #define write_queue_h
 +/* 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.
 + *
 + */
- struct write_queue {
-       struct bsc_fd bfd;
++#ifndef OSMO_WQUEUE_H
++#define OSMO_WQUEUE_H
 +
 +#include <osmocom/core/select.h>
 +#include <osmocom/core/msgb.h>
 +
-       int (*read_cb)(struct bsc_fd *fd);
-       int (*write_cb)(struct bsc_fd *fd, struct msgb *msg);
-       int (*except_cb)(struct bsc_fd *fd);
++struct osmo_wqueue {
++      struct osmo_fd bfd;
 +      unsigned int max_length;
 +      unsigned int current_length;
 +
 +      struct llist_head msg_queue;
 +
- 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);
++      int (*read_cb)(struct osmo_fd *fd);
++      int (*write_cb)(struct osmo_fd *fd, struct msgb *msg);
++      int (*except_cb)(struct osmo_fd *fd);
 +};
 +
++void osmo_wqueue_init(struct osmo_wqueue *queue, int max_length);
++void osmo_wqueue_clear(struct osmo_wqueue *queue);
++int osmo_wqueue_enqueue(struct osmo_wqueue *queue, struct msgb *data);
++int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what);
 +
 +#endif
index 8685fc9,0000000..a39d2d0
mode 100644,000000..100644
--- /dev/null
@@@ -1,6 -1,0 +1,6 @@@
- osmogsm_HEADERS = comp128.h gsm0808.h gsm48_ie.h mncc.h rxlev_stat.h \
++osmogsm_HEADERS = a5.h 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
index 0000000,0000000..2c630e5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,49 @@@
++/*
++ * a5.h
++ *
++ * Copyright (C) 2011  Sylvain Munaut <tnt@246tNt.com>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#ifndef __OSMO_A5_H__
++#define __OSMO_A5_H__
++
++#include <stdint.h>
++
++#include <osmocom/core/bits.h>
++
++static inline uint32_t
++osmo_a5_fn_count(uint32_t fn)
++{
++      int t1 = fn / (26 * 51);
++      int t2 = fn % 26;
++      int t3 = fn % 51;
++      return (t1 << 11) | (t3 << 5) | t2;
++}
++
++      /* Notes:
++       *  - key must be 8 bytes long (or NULL for A5/0)
++       *  - the dl and ul pointer must be either NULL or 114 bits long
++       *  - fn is the _real_ GSM frame number.
++       *    (converted internally to fn_count)
++       */
++void osmo_a5(int n, uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
++void osmo_a5_1(uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
++void osmo_a5_2(uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
++
++#endif /* __OSMO_A5_H__ */
index 0c034e4,0000000..1d8055e
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,40 @@@
-       struct bsc_fd fd;
 +/* minimalistic telnet/network interface it might turn into a wire interface */
 +/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#ifndef TELNET_INTERFACE_H
 +#define TELNET_INTERFACE_H
 +
 +#include <osmocom/core/logging.h>
 +#include <osmocom/core/select.h>
 +
 +#include <osmocom/vty/vty.h>
 +
 +struct telnet_connection {
 +      struct llist_head entry;
 +      void *priv;
++      struct osmo_fd fd;
 +      struct vty *vty;
 +      struct log_target *dbg;
 +};
 +
 +
 +int telnet_init(void *tall_ctx, void *priv, int port);
 +
 +#endif
index c5c8a21,0000000..e58bc28
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,32 @@@
- LIBVERSION=0:0:0
 +SUBDIRS=. vty codec gsm
 +
 +# This is _NOT_ the library release version, it's an API version.
 +# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
-                        process.c
++LIBVERSION=1:0:1
 +
 +INCLUDES = $(all_includes) -I$(top_srcdir)/include
 +AM_CFLAGS = -fPIC -Wall
 +
 +lib_LTLIBRARIES = libosmocore.la
 +
 +libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \
 +                       bitvec.c statistics.c \
 +                       write_queue.c utils.c \
 +                       logging.c logging_syslog.c rate_ctr.c \
 +                       gsmtap_util.c crc16.c panic.c backtrace.c \
- libosmocore_la_LDFLAGS = -ldl
++                       process.c conv.c application.c
 +
 +if ENABLE_PLUGIN
 +libosmocore_la_SOURCES += plugin.c
++libosmocore_la_LDFLAGS = -version-info $(LIBVERSION) -ldl
++else
++libosmocore_la_LDFLAGS = -version-info $(LIBVERSION)
 +endif
 +
 +if ENABLE_TALLOC
 +libosmocore_la_SOURCES += talloc.c
 +endif
 +
 +if ENABLE_MSGFILE
 +libosmocore_la_SOURCES += msgfile.c
 +endif
index 0000000,0000000..96b4204
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,49 @@@
++/* Utility functions to setup applications */
++/*
++ * (C) 2011 by Holger Hans Peter Freyther
++ *
++ * 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 <osmocom/core/application.h>
++#include <osmocom/core/logging.h>
++
++#include <signal.h>
++
++struct log_target *osmo_stderr_target;
++
++void osmo_init_ignore_signals(void)
++{
++      /* Signals that by default would terminate */
++      signal(SIGPIPE, SIG_IGN);
++      signal(SIGALRM, SIG_IGN);
++      signal(SIGHUP, SIG_IGN);
++      signal(SIGIO, SIG_IGN);
++}
++
++int osmo_init_logging(const struct log_info *log_info)
++{
++      log_init(log_info);
++      osmo_stderr_target = log_target_create_stderr();
++      if (!osmo_stderr_target)
++              return -1;
++
++      log_add_target(osmo_stderr_target);
++      log_set_all_filter(osmo_stderr_target, 1);
++      return 0;
++}
index ecd6b9c,0000000..8281fad
mode 100644,000000..100644
--- /dev/null
@@@ -1,50 -1,0 +1,50 @@@
- void generate_backtrace()
 +/*
 + * (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>
 + * (C) 2010 by Nico Golde <nico@ngolde.de>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <osmocom/core/utils.h>
 +#include "config.h"
 +
 +#ifdef HAVE_EXECINFO_H
 +#include <execinfo.h>
++void osmo_generate_backtrace()
 +{
 +      int i, nptrs;
 +      void *buffer[100];
 +      char **strings;
 +
 +      nptrs = backtrace(buffer, ARRAY_SIZE(buffer));
 +      printf("backtrace() returned %d addresses\n", nptrs);
 +
 +      strings = backtrace_symbols(buffer, nptrs);
 +      if (!strings)
 +              return;
 +
 +      for (i = 1; i < nptrs; i++)
 +              printf("%s\n", strings[i]);
 +
 +      free(strings);
 +}
 +#endif
index f8a0601,0000000..5a54c42
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,11 @@@
 +# This is _NOT_ the library release version, it's an API version.
 +# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
 +LIBVERSION=0:0:0
 +
 +INCLUDES = $(all_includes) -I$(top_srcdir)/include
 +AM_CFLAGS = -fPIC -Wall
 +
 +lib_LTLIBRARIES = libosmocodec.la
 +
 +libosmocodec_la_SOURCES = gsm610.c gsm620.c gsm660.c gsm690.c
++libosmocodec_la_LDFALGS = -version-info $(LIBVERSION)
index 0000000,0000000..70bdffb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,496 @@@
++/*
++ * conv.c
++ *
++ * Generic convolutional encoding / decoding
++ *
++ * Copyright (C) 2011  Sylvain Munaut <tnt@246tNt.com>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <alloca.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <osmocom/core/bits.h>
++#include <osmocom/core/conv.h>
++
++
++/* ------------------------------------------------------------------------ */
++/* Encoding                                                                 */
++/* ------------------------------------------------------------------------ */
++
++void
++osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
++                      const struct osmo_conv_code *code)
++{
++      memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
++      encoder->code = code;
++}
++
++static inline int
++_conv_encode_do_output(struct osmo_conv_encoder *encoder,
++                       uint8_t out, ubit_t *output)
++{
++      const struct osmo_conv_code *code = encoder->code;
++      int o_idx = 0;
++      int j;
++
++      if (code->puncture) {
++              for (j=0; j<code->N; j++)
++              {
++                      int bit_no = code->N - j - 1;
++                      int r_idx = encoder->i_idx * code->N + j;
++
++                      if (code->puncture[encoder->p_idx] == r_idx)
++                              encoder->p_idx++;
++                      else
++                              output[o_idx++] = (out >> bit_no) & 1;
++              }
++      } else {
++              for (j=0; j<code->N; j++)
++              {
++                      int bit_no = code->N - j - 1;
++                      output[o_idx++] = (out >> bit_no) & 1;
++              }
++      }
++
++      return o_idx;
++}
++
++int
++osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
++                     const ubit_t *input, ubit_t *output, int n)
++{
++      const struct osmo_conv_code *code = encoder->code;
++      uint8_t state;
++      int i;
++      int o_idx;
++
++      o_idx = 0;
++      state = encoder->state;
++
++      for (i=0; i<n; i++) {
++              int bit = input[i];
++              uint8_t out;
++
++              out   = code->next_output[state][bit];
++              state = code->next_state[state][bit];
++
++              o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
++
++              encoder->i_idx++;
++      }
++
++      encoder->state = state;
++
++      return o_idx;
++}
++
++int
++osmo_conv_encode_finish(struct osmo_conv_encoder *encoder,
++                        ubit_t *output)
++{
++      const struct osmo_conv_code *code = encoder->code;
++      uint8_t state;
++      int n;
++      int i;
++      int o_idx;
++
++      n = code->K - 1;
++
++      o_idx = 0;
++      state = encoder->state;
++
++      for (i=0; i<n; i++) {
++              uint8_t out;
++
++              if (code->next_term_output) {
++                      out   = code->next_term_output[state];
++                      state = code->next_term_state[state];
++              } else {
++                      out   = code->next_output[state][0];
++                      state = code->next_state[state][0];
++              }
++
++              o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
++
++              encoder->i_idx++;
++      }
++
++      encoder->state = state;
++
++      return o_idx;
++}
++
++int
++osmo_conv_encode(const struct osmo_conv_code *code,
++                 const ubit_t *input, ubit_t *output)
++{
++      struct osmo_conv_encoder encoder;
++      int l;
++
++      osmo_conv_encode_init(&encoder, code);
++      l  = osmo_conv_encode_raw(&encoder, input, output, code->len);
++      l += osmo_conv_encode_finish(&encoder, &output[l]);
++
++      return l;
++}
++
++
++/* ------------------------------------------------------------------------ */
++/* Decoding (viterbi)                                                       */
++/* ------------------------------------------------------------------------ */
++
++#define MAX_AE 0x00ffffff
++
++void
++osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
++                      const struct osmo_conv_code *code, int len)
++{
++      int n_states;
++
++      /* Init */
++      if (len <= 0)
++              len =  code->len;
++
++      n_states = 1 << (code->K - 1);
++
++      memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
++
++      decoder->code = code;
++      decoder->n_states = n_states;
++      decoder->len = len;
++
++      /* Allocate arrays */
++      decoder->ae      = malloc(sizeof(unsigned int) * n_states);
++      decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
++
++      decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
++
++      /* Classic reset */
++      osmo_conv_decode_reset(decoder);
++}
++
++void
++osmo_conv_decode_reset(struct osmo_conv_decoder *decoder)
++{
++      int i;
++
++      /* Reset indexes */
++      decoder->o_idx = 0;
++      decoder->p_idx = 0;
++
++      /* Initial error (only state 0 is valid) */
++      decoder->ae[0] = 0;
++      for (i=1; i<decoder->n_states; i++) {
++              decoder->ae[i] = MAX_AE;
++      }
++}
++
++void
++osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
++{
++      free(decoder->ae);
++      free(decoder->ae_next);
++      free(decoder->state_history);
++
++      memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
++}
++
++int
++osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
++                      const sbit_t *input, int n)
++{
++      const struct osmo_conv_code *code = decoder->code;
++
++      int i, s, b, j;
++
++      int n_states;
++      unsigned int *ae;
++      unsigned int *ae_next;
++      uint8_t *state_history;
++      sbit_t *in_sym;
++
++      int i_idx, p_idx;
++
++      /* Prepare */
++      n_states = decoder->n_states;
++
++      ae      = decoder->ae;
++      ae_next = decoder->ae_next;
++      state_history = &decoder->state_history[n_states * decoder->o_idx];
++
++      in_sym  = alloca(sizeof(sbit_t) * code->N);
++
++      i_idx = 0;
++      p_idx = decoder->p_idx;
++
++      /* Scan the treillis */
++      for (i=0; i<n; i++)
++      {
++              /* Reset next accumulated error */
++              for (s=0; s<n_states; s++) {
++                      ae_next[s] = MAX_AE;
++              }
++
++              /* Get input */
++              if (code->puncture) {
++                      /* Hard way ... */
++                      for (j=0; j<code->N; j++) {
++                              int idx = ((decoder->o_idx + i) * code->N) + j;
++                              if (idx == code->puncture[p_idx]) {
++                                      in_sym[j] = 0;  /* Undefined */
++                                      p_idx++;
++                              } else {
++                                      in_sym[j] = input[i_idx];
++                                      i_idx++;
++                              }
++                      }
++              } else {
++                      /* Easy, just copy N bits */
++                      memcpy(in_sym, &input[i_idx], code->N);
++                      i_idx += code->N;
++              }
++
++              /* Scan all state */
++              for (s=0; s<n_states; s++)
++              {
++                      /* Scan possible input bits */
++                      for (b=0; b<2; b++)
++                      {
++                              int nae, ov, e;
++                              uint8_t m;
++
++                              /* Next output and state */
++                              uint8_t out   = code->next_output[s][b];
++                              uint8_t state = code->next_state[s][b];
++
++                              /* New error for this path */
++                              nae = ae[s];                    /* start from last error */
++                              m = 1 << (code->N - 1);         /* mask for 'out' bit selection */
++
++                              for (j=0; j<code->N; j++) {
++                                      ov = (out & m) ? -127 : 127; /* sbit_t value for it */
++                                      e = ((int)in_sym[j]) - ov;   /* raw error for this bit */
++                                      nae += (e * e) >> 9;         /* acc the squared/scaled value */
++                                      m >>= 1;                     /* next mask bit */
++                              }
++
++                              /* Is it survivor ? */
++                              if (ae_next[state] > nae) {
++                                      ae_next[state] = nae;
++                                      state_history[(n_states * i) + state] = s;
++                              }
++                      }
++              }
++
++              /* Copy accumulated error */
++              memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
++      }
++
++      /* Update decoder state */
++      decoder->p_idx = p_idx;
++      decoder->o_idx += n;
++
++      return i_idx;
++}
++
++int
++osmo_conv_decode_finish(struct osmo_conv_decoder *decoder,
++                        const sbit_t *input)
++{
++      const struct osmo_conv_code *code = decoder->code;
++
++      int i, s, j;
++
++      int n_states;
++      unsigned int *ae;
++      unsigned int *ae_next;
++      uint8_t *state_history;
++      sbit_t *in_sym;
++
++      int i_idx, p_idx;
++
++      /* Prepare */
++      n_states = decoder->n_states;
++
++      ae      = decoder->ae;
++      ae_next = decoder->ae_next;
++      state_history = &decoder->state_history[n_states * decoder->o_idx];
++
++      in_sym  = alloca(sizeof(sbit_t) * code->N);
++
++      i_idx = 0;
++      p_idx = decoder->p_idx;
++
++      /* Scan the treillis */
++      for (i=0; i<code->K-1; i++)
++      {
++              /* Reset next accumulated error */
++              for (s=0; s<n_states; s++) {
++                      ae_next[s] = MAX_AE;
++              }
++
++              /* Get input */
++              if (code->puncture) {
++                      /* Hard way ... */
++                      for (j=0; j<code->N; j++) {
++                              int idx = ((decoder->o_idx + i) * code->N) + j;
++                              if (idx == code->puncture[p_idx]) {
++                                      in_sym[j] = 0;  /* Undefined */
++                                      p_idx++;
++                              } else {
++                                      in_sym[j] = input[i_idx];
++                                      i_idx++;
++                              }
++                      }
++              } else {
++                      /* Easy, just copy N bits */
++                      memcpy(in_sym, &input[i_idx], code->N);
++                      i_idx += code->N;
++              }
++
++              /* Scan all state */
++              for (s=0; s<n_states; s++)
++              {
++                      int nae, ov, e;
++                      uint8_t m;
++
++                      /* Next output and state */
++                      uint8_t out;
++                      uint8_t state;
++
++                      if (code->next_term_output) {
++                              out   = code->next_term_output[s];
++                              state = code->next_term_state[s];
++                      } else {
++                              out   = code->next_output[s][0];
++                              state = code->next_state[s][0];
++                      }
++
++                      /* New error for this path */
++                      nae = ae[s];                    /* start from last error */
++                      m = 1 << (code->N - 1);         /* mask for 'out' bit selection */
++
++                      for (j=0; j<code->N; j++) {
++                              int is = (int)in_sym[j];
++                              if (is) {
++                                      ov = (out & m) ? -127 : 127; /* sbit_t value for it */
++                                      e = is - ov;                 /* raw error for this bit */
++                                      nae += (e * e) >> 9;         /* acc the squared/scaled value */
++                              }
++                              m >>= 1;                     /* next mask bit */
++                      }
++
++                      /* Is it survivor ? */
++                      if (ae_next[state] > nae) {
++                              ae_next[state] = nae;
++                              state_history[(n_states * i) + state] = s;
++                      }
++              }
++
++              /* Copy accumulated error */
++              memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
++      }
++
++      /* Update decoder state */
++      decoder->p_idx = p_idx;
++      decoder->o_idx += code->K - 1;
++
++      return i_idx;
++}
++
++int
++osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
++                            ubit_t *output, int has_finish)
++{
++      const struct osmo_conv_code *code = decoder->code;
++
++      int min_ae;
++      uint8_t min_state, cur_state;
++      int i, s, n;
++
++      uint8_t *sh_ptr;
++
++      /* Find state with least error */
++      min_ae = MAX_AE;
++      min_state = 0xff;
++
++      for (s=0; s<decoder->n_states; s++)
++      {
++              if (decoder->ae[s] < min_ae) {
++                      min_ae = decoder->ae[s];
++                      min_state = s;
++              }
++      }
++
++      if (min_state == 0xff)
++              return -1;
++
++      /* Traceback */
++      cur_state = min_state;
++
++      n = decoder->o_idx;
++
++      sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
++
++              /* No output for the K-1 termination input bits */
++      if (has_finish) {
++              for (i=0; i<code->K-1; i++) {
++                      cur_state = sh_ptr[cur_state];
++                      sh_ptr -= decoder->n_states;
++              }
++              n -= code->K - 1;
++      }
++
++              /* Generate output backward */
++      for (i=n-1; i>=0; i--)
++      {
++              min_state = cur_state;
++              cur_state = sh_ptr[cur_state];
++
++              sh_ptr -= decoder->n_states;
++
++              if (code->next_state[cur_state][0] == min_state)
++                      output[i] = 0;
++              else
++                      output[i] = 1;
++      }
++
++      return min_ae;
++}
++
++int
++osmo_conv_decode(const struct osmo_conv_code *code,
++                 const sbit_t *input, ubit_t *output)
++{
++      struct osmo_conv_decoder decoder;
++      int rv, l;
++
++      osmo_conv_decode_init(&decoder, code, 0);
++
++      l = osmo_conv_decode_scan(&decoder, input, code->len);
++      l = osmo_conv_decode_finish(&decoder, &input[l]);
++
++      rv = osmo_conv_decode_get_output(&decoder, output, 1);
++
++      osmo_conv_decode_deinit(&decoder);
++
++      return rv;
++}
index 3a0d0dd,0000000..2741cf5
mode 100644,000000..100644
--- /dev/null
@@@ -1,62 -1,0 +1,62 @@@
- uint16_t const crc16_table[256] = {
 +/*
 + * This was copied from the linux kernel and adjusted for our types.
 + */
 +/*
 + *      crc16.c
 + *
 + * This source code is licensed under the GNU General Public License,
 + * Version 2. See the file COPYING for more details.
 + */
 +
 +#include <osmocom/core/crc16.h>
 +
 +/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
- uint16_t crc16(uint16_t crc, uint8_t const *buffer, size_t len)
++uint16_t const osmo_crc16_table[256] = {
 +      0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
 +      0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
 +      0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
 +      0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
 +      0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
 +      0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
 +      0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
 +      0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
 +      0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
 +      0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
 +      0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
 +      0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
 +      0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
 +      0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
 +      0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
 +      0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
 +      0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
 +      0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
 +      0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
 +      0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
 +      0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
 +      0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
 +      0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
 +      0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
 +      0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
 +      0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
 +      0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
 +      0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
 +      0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
 +      0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
 +      0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
 +      0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
 +};
 +
 +/**
 + * crc16 - compute the CRC-16 for the data buffer
 + * @crc:      previous CRC value
 + * @buffer:   data pointer
 + * @len:      number of bytes in the buffer
 + *
 + * Returns the updated CRC value.
 + */
-               crc = crc16_byte(crc, *buffer++);
++uint16_t osmo_crc16(uint16_t crc, uint8_t const *buffer, size_t len)
 +{
 +      while (len--)
++              crc = osmo_crc16_byte(crc, *buffer++);
 +      return crc;
 +}
index a8c2e56,0000000..fb4a8cb
mode 100644,000000..100644
--- /dev/null
@@@ -1,13 -1,0 +1,14 @@@
- libosmogsm_la_SOURCES = rxlev_stat.c tlv_parser.c comp128.c gsm_utils.c \
 +# This is _NOT_ the library release version, it's an API version.
 +# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
 +LIBVERSION=0:0:0
 +
 +INCLUDES = $(all_includes) -I$(top_srcdir)/include
 +AM_CFLAGS = -fPIC -Wall
 +
 +lib_LTLIBRARIES = libosmogsm.la
 +
++libosmogsm_la_SOURCES = a5.c rxlev_stat.c tlv_parser.c comp128.c gsm_utils.c \
 +                        rsl.c gsm48.c gsm48_ie.c gsm0808.c \
 +                      gprs_cipher_core.c gsm0480.c
++libosmogsm_la_LDFLAGS = -version-info $(LIBVERSION)
 +libosmogsm_la_LIBADD = $(top_builddir)/src/libosmocore.la
index 0000000,0000000..d3f2b2c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,311 @@@
++/*
++ * a5.c
++ *
++ * Full reimplementation of A5/1,2 (split and threadsafe)
++ *
++ * The logic behind the algorithm is taken from "A pedagogical implementation
++ * of the GSM A5/1 and A5/2 "voice privacy" encryption algorithms." by
++ * Marc Briceno, Ian Goldberg, and David Wagner.
++ *
++ * Copyright (C) 2011  Sylvain Munaut <tnt@246tNt.com>
++ *
++ * All Rights Reserved
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
++ */
++
++#include <string.h>
++
++#include <osmocom/gsm/a5.h>
++
++void
++osmo_a5(int n, uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
++{
++      switch (n)
++      {
++      case 0:
++              if (dl)
++                      memset(dl, 0x00, 114);
++              if (ul)
++                      memset(ul, 0x00, 114);
++              break;
++
++      case 1:
++              osmo_a5_1(key, fn, dl, ul);
++              break;
++
++      case 2:
++              osmo_a5_2(key, fn, dl, ul);
++              break;
++
++      default:
++              /* a5/[3..7] not supported here/yet */
++              break;
++      }
++}
++
++
++/* ------------------------------------------------------------------------ */
++/* A5/1&2 common stuff                                                                     */
++/* ------------------------------------------------------------------------ */
++
++#define A5_R1_LEN     19
++#define A5_R2_LEN     22
++#define A5_R3_LEN     23
++#define A5_R4_LEN     17      /* A5/2 only */
++
++#define A5_R1_MASK    ((1<<A5_R1_LEN)-1)
++#define A5_R2_MASK    ((1<<A5_R2_LEN)-1)
++#define A5_R3_MASK    ((1<<A5_R3_LEN)-1)
++#define A5_R4_MASK    ((1<<A5_R4_LEN)-1)
++
++#define A5_R1_TAPS    0x072000 /* x^19 + x^5 + x^2 + x + 1 */
++#define A5_R2_TAPS    0x300000 /* x^22 + x + 1 */
++#define A5_R3_TAPS    0x700080 /* x^23 + x^15 + x^2 + x + 1 */
++#define A5_R4_TAPS    0x010800 /* x^17 + x^5 + 1 */
++
++static inline uint32_t
++_a5_12_parity(uint32_t x)
++{
++      x ^= x >> 16;
++      x ^= x >> 8;
++      x ^= x >> 4;
++      x ^= x >> 2;
++      x ^= x >> 1;
++      return x & 1;
++}
++
++static inline uint32_t
++_a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
++{
++      return (!!v1 + !!v2 + !!v3) >= 2;
++}
++
++static inline uint32_t
++_a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
++{
++      return ((r << 1) & mask) | _a5_12_parity(r & taps);
++}
++
++
++/* ------------------------------------------------------------------------ */
++/* A5/1                                                                     */
++/* ------------------------------------------------------------------------ */
++
++#define A51_R1_CLKBIT 0x000100
++#define A51_R2_CLKBIT 0x000400
++#define A51_R3_CLKBIT 0x000400
++
++static inline void
++_a5_1_clock(uint32_t r[], int force)
++{
++      int cb[3], maj;
++
++      cb[0] = !!(r[0] & A51_R1_CLKBIT);
++      cb[1] = !!(r[1] & A51_R2_CLKBIT);
++      cb[2] = !!(r[2] & A51_R3_CLKBIT);
++
++      maj = _a5_12_majority(cb[0], cb[1], cb[2]);
++
++      if (force || (maj == cb[0]))
++              r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
++
++      if (force || (maj == cb[1]))
++              r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
++
++      if (force || (maj == cb[2]))
++              r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
++}
++
++static inline uint8_t
++_a5_1_get_output(uint32_t r[])
++{
++      return  (r[0] >> (A5_R1_LEN-1)) ^
++              (r[1] >> (A5_R2_LEN-1)) ^
++              (r[2] >> (A5_R3_LEN-1));
++}
++
++void
++osmo_a5_1(uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
++{
++      uint32_t r[3] = {0, 0, 0};
++      uint32_t fn_count;
++      uint32_t b;
++      int i;
++
++      /* Key load */
++      for (i=0; i<64; i++)
++      {
++              b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
++
++              _a5_1_clock(r, 1);
++
++              r[0] ^= b;
++              r[1] ^= b;
++              r[2] ^= b;
++      }
++
++      /* Frame count load */
++      fn_count = osmo_a5_fn_count(fn);
++
++      for (i=0; i<22; i++)
++      {
++              b = (fn_count >> i) & 1;
++
++              _a5_1_clock(r, 1);
++
++              r[0] ^= b;
++              r[1] ^= b;
++              r[2] ^= b;
++      }
++
++      /* Mix */
++      for (i=0; i<100; i++)
++      {
++              _a5_1_clock(r, 0);
++      }
++
++      /* Output */
++      for (i=0; i<114; i++) {
++              _a5_1_clock(r, 0);
++              if (dl)
++                      dl[i] = _a5_1_get_output(r);
++      }
++
++      for (i=0; i<114; i++) {
++              _a5_1_clock(r, 0);
++              if (ul)
++                      ul[i] = _a5_1_get_output(r);
++      }
++}
++
++
++/* ------------------------------------------------------------------------ */
++/* A5/2                                                                     */
++/* ------------------------------------------------------------------------ */
++
++#define A52_R4_CLKBIT0        0x000400
++#define A52_R4_CLKBIT1        0x000008
++#define A52_R4_CLKBIT2        0x000080
++
++static inline void
++_a5_2_clock(uint32_t r[], int force)
++{
++      int cb[3], maj;
++
++      cb[0] = !!(r[3] & A52_R4_CLKBIT0);
++      cb[1] = !!(r[3] & A52_R4_CLKBIT1);
++      cb[2] = !!(r[3] & A52_R4_CLKBIT2);
++
++      maj = (cb[0] + cb[1] + cb[2]) >= 2;
++
++      if (force || (maj == cb[0]))
++              r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
++
++      if (force || (maj == cb[1]))
++              r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
++
++      if (force || (maj == cb[2]))
++              r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
++
++      r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
++}
++
++static inline uint8_t
++_a5_2_get_output(uint32_t r[], uint8_t *db)
++{
++      uint8_t cb, tb;
++
++      tb =    (r[0] >> (A5_R1_LEN-1)) ^
++              (r[1] >> (A5_R2_LEN-1)) ^
++              (r[2] >> (A5_R3_LEN-1));
++
++      cb = *db;
++
++      *db = ( tb ^
++              _a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000,  r[0] & 0x1000) ^
++              _a5_12_majority(~r[1] & 0x10000,  r[1] & 0x02000,  r[1] & 0x0200) ^
++              _a5_12_majority( r[2] & 0x40000,  r[2] & 0x10000, ~r[2] & 0x2000)
++      );
++
++      return cb;
++}
++
++void
++osmo_a5_2(uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
++{
++      uint32_t r[4] = {0, 0, 0, 0};
++      uint32_t fn_count;
++      uint32_t b;
++      uint8_t db = 0, o;
++      int i;
++
++      /* Key load */
++      for (i=0; i<64; i++)
++      {
++              b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
++
++              _a5_2_clock(r, 1);
++
++              r[0] ^= b;
++              r[1] ^= b;
++              r[2] ^= b;
++              r[3] ^= b;
++      }
++
++      /* Frame count load */
++      fn_count = osmo_a5_fn_count(fn);
++
++      for (i=0; i<22; i++)
++      {
++              b = (fn_count >> i) & 1;
++
++              _a5_2_clock(r, 1);
++
++              r[0] ^= b;
++              r[1] ^= b;
++              r[2] ^= b;
++              r[3] ^= b;
++      }
++
++      r[0] |= 1 << 15;
++      r[1] |= 1 << 16;
++      r[2] |= 1 << 18;
++      r[3] |= 1 << 10;
++
++      /* Mix */
++      for (i=0; i<100; i++)
++      {
++              _a5_2_clock(r, 0);
++      }
++
++      _a5_2_get_output(r, &db);
++
++
++      /* Output */
++      for (i=0; i<114; i++) {
++              _a5_2_clock(r, 0);
++              o = _a5_2_get_output(r, &db);
++              if (dl)
++                      dl[i] = o;
++      }
++
++      for (i=0; i<114; i++) {
++              _a5_2_clock(r, 0);
++              o = _a5_2_get_output(r, &db);
++              if (ul)
++                      ul[i] = o;
++      }
++}
index 0ff85e2,0000000..7884be0
mode 100644,000000..100644
--- /dev/null
@@@ -1,99 -1,0 +1,99 @@@
-       return plugin_load_all(path);
 +/* GPRS LLC cipher core infrastructure */
 +
 +/* (C) 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.
 + *
 + */
 +
 +#include <errno.h>
 +#include <stdint.h>
 +
 +#include <osmocom/core/utils.h>
 +#include <osmocom/core/linuxlist.h>
 +#include <osmocom/core/plugin.h>
 +
 +#include <osmocom/crypt/gprs_cipher.h>
 +
 +static LLIST_HEAD(gprs_ciphers);
 +
 +static struct gprs_cipher_impl *selected_ciphers[_GPRS_ALGO_NUM];
 +
 +/* register a cipher with the core */
 +int gprs_cipher_register(struct gprs_cipher_impl *ciph)
 +{
 +      if (ciph->algo > ARRAY_SIZE(selected_ciphers))
 +              return -ERANGE;
 +
 +      llist_add_tail(&ciph->list, &gprs_ciphers);
 +
 +      /* check if we want to select this implementation over others */
 +      if (!selected_ciphers[ciph->algo] ||
 +          (selected_ciphers[ciph->algo]->priority > ciph->priority))
 +              selected_ciphers[ciph->algo] = ciph;
 +
 +      return 0;
 +}
 +
 +/* load all available GPRS cipher plugins */
 +int gprs_cipher_load(const char *path)
 +{
 +      /* load all plugins available from path */
++      return osmo_plugin_load_all(path);
 +}
 +
 +/* function to be called by core code */
 +int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo,
 +                  uint64_t kc, uint32_t iv, enum gprs_cipher_direction dir)
 +{
 +      if (algo > ARRAY_SIZE(selected_ciphers))
 +              return -ERANGE;
 +
 +      if (!selected_ciphers[algo])
 +              return -EINVAL;
 +
 +      if (len > GSM0464_CIPH_MAX_BLOCK)
 +              return -ERANGE;
 +
 +      /* run the actual cipher from the plugin */
 +      return selected_ciphers[algo]->run(out, len, kc, iv, dir);
 +}
 +
 +int gprs_cipher_supported(enum gprs_ciph_algo algo)
 +{
 +      if (algo > ARRAY_SIZE(selected_ciphers))
 +              return -ERANGE;
 +
 +      if (selected_ciphers[algo])
 +              return 1;
 +
 +      return 0;
 +}
 +
 +/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */
 +uint32_t gprs_cipher_gen_input_ui(uint32_t iov_ui, uint8_t sapi, uint32_t lfn, uint32_t oc)
 +{
 +      uint32_t sx = ((1<<27) * sapi) + (1<<31);
 +
 +      return (iov_ui ^ sx) + lfn + oc;
 +}
 +
 +/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */
 +uint32_t gprs_cipher_gen_input_i(uint32_t iov_i, uint32_t lfn, uint32_t oc)
 +{
 +      return iov_i + lfn + oc;
 +}
index 436bf14,0000000..d034589
mode 100644,000000..100644
--- /dev/null
@@@ -1,415 -1,0 +1,415 @@@
-       buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3);
 +/* GSM Mobile Radio Interface Layer 3 messages
 + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
 +
 +/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
 + * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <stdint.h>
 +#include <stdio.h>
 +#include <string.h>
 +
 +#include <arpa/inet.h>
 +
 +#include <osmocom/core/utils.h>
 +#include <osmocom/gsm/tlv.h>
 +#include <osmocom/gsm/gsm48.h>
 +
 +#include <osmocom/gsm/protocol/gsm_04_08.h>
 +
 +const struct tlv_definition gsm48_att_tlvdef = {
 +      .def = {
 +              [GSM48_IE_MOBILE_ID]    = { TLV_TYPE_TLV },
 +              [GSM48_IE_NAME_LONG]    = { TLV_TYPE_TLV },
 +              [GSM48_IE_NAME_SHORT]   = { TLV_TYPE_TLV },
 +              [GSM48_IE_UTC]          = { TLV_TYPE_TV },
 +              [GSM48_IE_NET_TIME_TZ]  = { TLV_TYPE_FIXED, 7 },
 +              [GSM48_IE_LSA_IDENT]    = { TLV_TYPE_TLV },
 +
 +              [GSM48_IE_BEARER_CAP]   = { TLV_TYPE_TLV },
 +              [GSM48_IE_CAUSE]        = { TLV_TYPE_TLV },
 +              [GSM48_IE_CC_CAP]       = { TLV_TYPE_TLV },
 +              [GSM48_IE_ALERT]        = { TLV_TYPE_TLV },
 +              [GSM48_IE_FACILITY]     = { TLV_TYPE_TLV },
 +              [GSM48_IE_PROGR_IND]    = { TLV_TYPE_TLV },
 +              [GSM48_IE_AUX_STATUS]   = { TLV_TYPE_TLV },
 +              [GSM48_IE_NOTIFY]       = { TLV_TYPE_TV },
 +              [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
 +              [GSM48_IE_SIGNAL]       = { TLV_TYPE_TV },
 +              [GSM48_IE_CONN_BCD]     = { TLV_TYPE_TLV },
 +              [GSM48_IE_CONN_SUB]     = { TLV_TYPE_TLV },
 +              [GSM48_IE_CALLING_BCD]  = { TLV_TYPE_TLV },
 +              [GSM48_IE_CALLING_SUB]  = { TLV_TYPE_TLV },
 +              [GSM48_IE_CALLED_BCD]   = { TLV_TYPE_TLV },
 +              [GSM48_IE_CALLED_SUB]   = { TLV_TYPE_TLV },
 +              [GSM48_IE_REDIR_BCD]    = { TLV_TYPE_TLV },
 +              [GSM48_IE_REDIR_SUB]    = { TLV_TYPE_TLV },
 +              [GSM48_IE_LOWL_COMPAT]  = { TLV_TYPE_TLV },
 +              [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
 +              [GSM48_IE_USER_USER]    = { TLV_TYPE_TLV },
 +              [GSM48_IE_SS_VERS]      = { TLV_TYPE_TLV },
 +              [GSM48_IE_MORE_DATA]    = { TLV_TYPE_T },
 +              [GSM48_IE_CLIR_SUPP]    = { TLV_TYPE_T },
 +              [GSM48_IE_CLIR_INVOC]   = { TLV_TYPE_T },
 +              [GSM48_IE_REV_C_SETUP]  = { TLV_TYPE_T },
 +              [GSM48_IE_REPEAT_CIR]   = { TLV_TYPE_T },
 +              [GSM48_IE_REPEAT_SEQ]   = { TLV_TYPE_T },
 +              /* FIXME: more elements */
 +      },
 +};
 +
 +/* RR elements */
 +const struct tlv_definition gsm48_rr_att_tlvdef = {
 +      .def = {
 +              /* NOTE: Don't add IE 17 = MOBILE_ID here, it already used. */
 +              [GSM48_IE_VGCS_TARGET]          = { TLV_TYPE_TLV },
 +              [GSM48_IE_FRQSHORT_AFTER]       = { TLV_TYPE_FIXED, 9 },
 +              [GSM48_IE_MUL_RATE_CFG]         = { TLV_TYPE_TLV },
 +              [GSM48_IE_FREQ_L_AFTER]         = { TLV_TYPE_TLV },
 +              [GSM48_IE_MSLOT_DESC]           = { TLV_TYPE_TLV },
 +              [GSM48_IE_CHANMODE_2]           = { TLV_TYPE_TV },
 +              [GSM48_IE_FRQSHORT_BEFORE]      = { TLV_TYPE_FIXED, 9 },
 +              [GSM48_IE_CHANMODE_3]           = { TLV_TYPE_TV },
 +              [GSM48_IE_CHANMODE_4]           = { TLV_TYPE_TV },
 +              [GSM48_IE_CHANMODE_5]           = { TLV_TYPE_TV },
 +              [GSM48_IE_CHANMODE_6]           = { TLV_TYPE_TV },
 +              [GSM48_IE_CHANMODE_7]           = { TLV_TYPE_TV },
 +              [GSM48_IE_CHANMODE_8]           = { TLV_TYPE_TV },
 +              [GSM48_IE_FREQ_L_BEFORE]        = { TLV_TYPE_TLV },
 +              [GSM48_IE_CH_DESC_1_BEFORE]     = { TLV_TYPE_FIXED, 3 },
 +              [GSM48_IE_CH_DESC_2_BEFORE]     = { TLV_TYPE_FIXED, 3 },
 +              [GSM48_IE_F_CH_SEQ_BEFORE]      = { TLV_TYPE_FIXED, 9 },
 +              [GSM48_IE_CLASSMARK3]           = { TLV_TYPE_TLV },
 +              [GSM48_IE_MA_BEFORE]            = { TLV_TYPE_TLV },
 +              [GSM48_IE_RR_PACKET_UL]         = { TLV_TYPE_TLV },
 +              [GSM48_IE_RR_PACKET_DL]         = { TLV_TYPE_TLV },
 +              [GSM48_IE_CELL_CH_DESC]         = { TLV_TYPE_FIXED, 16 },
 +              [GSM48_IE_CHANMODE_1]           = { TLV_TYPE_TV },
 +              [GSM48_IE_CHDES_2_AFTER]        = { TLV_TYPE_FIXED, 3 },
 +              [GSM48_IE_MODE_SEC_CH]          = { TLV_TYPE_TV },
 +              [GSM48_IE_F_CH_SEQ_AFTER]               = { TLV_TYPE_FIXED, 9 },
 +              [GSM48_IE_MA_AFTER]             = { TLV_TYPE_TLV },
 +              [GSM48_IE_BA_RANGE]             = { TLV_TYPE_TLV },
 +              [GSM48_IE_GROUP_CHDES]          = { TLV_TYPE_TLV },
 +              [GSM48_IE_BA_LIST_PREF]         = { TLV_TYPE_TLV },
 +              [GSM48_IE_MOB_OVSERV_DIF]       = { TLV_TYPE_TLV },
 +              [GSM48_IE_REALTIME_DIFF]        = { TLV_TYPE_TLV },
 +              [GSM48_IE_START_TIME]           = { TLV_TYPE_FIXED, 2 },
 +              [GSM48_IE_TIMING_ADVANCE]       = { TLV_TYPE_TV },
 +              [GSM48_IE_GROUP_CIP_SEQ]        = { TLV_TYPE_SINGLE_TV },
 +              [GSM48_IE_CIP_MODE_SET]         = { TLV_TYPE_SINGLE_TV },
 +              [GSM48_IE_GPRS_RESUMPT]         = { TLV_TYPE_SINGLE_TV },
 +              [GSM48_IE_SYNC_IND]             = { TLV_TYPE_SINGLE_TV },
 +      },
 +};
 +
 +/* MM elements */
 +const struct tlv_definition gsm48_mm_att_tlvdef = {
 +      .def = {
 +              [GSM48_IE_MOBILE_ID]            = { TLV_TYPE_TLV },
 +              [GSM48_IE_NAME_LONG]            = { TLV_TYPE_TLV },
 +              [GSM48_IE_NAME_SHORT]           = { TLV_TYPE_TLV },
 +              [GSM48_IE_UTC]                  = { TLV_TYPE_TV },
 +              [GSM48_IE_NET_TIME_TZ]          = { TLV_TYPE_FIXED, 7 },
 +              [GSM48_IE_LSA_IDENT]            = { TLV_TYPE_TLV },
 +
 +              [GSM48_IE_LOCATION_AREA]        = { TLV_TYPE_FIXED, 5 },
 +              [GSM48_IE_PRIORITY_LEV]         = { TLV_TYPE_SINGLE_TV },
 +              [GSM48_IE_FOLLOW_ON_PROC]       = { TLV_TYPE_T },
 +              [GSM48_IE_CTS_PERMISSION]       = { TLV_TYPE_T },
 +      },
 +};
 +
 +static const struct value_string rr_cause_names[] = {
 +      { GSM48_RR_CAUSE_NORMAL,                "Normal event" },
 +      { GSM48_RR_CAUSE_ABNORMAL_UNSPEC,       "Abnormal release, unspecified" },
 +      { GSM48_RR_CAUSE_ABNORMAL_UNACCT,       "Abnormal release, channel unacceptable" },
 +      { GSM48_RR_CAUSE_ABNORMAL_TIMER,        "Abnormal release, timer expired" },
 +      { GSM48_RR_CAUSE_ABNORMAL_NOACT,        "Abnormal release, no activity on radio path" },
 +      { GSM48_RR_CAUSE_PREMPTIVE_REL,         "Preemptive release" },
 +      { GSM48_RR_CAUSE_HNDOVER_IMP,           "Handover impossible, timing advance out of range" },
 +      { GSM48_RR_CAUSE_CHAN_MODE_UNACCT,      "Channel mode unacceptable" },
 +      { GSM48_RR_CAUSE_FREQ_NOT_IMPL,         "Frequency not implemented" },
 +      { GSM48_RR_CAUSE_CALL_CLEARED,          "Call already cleared" },
 +      { GSM48_RR_CAUSE_SEMANT_INCORR,         "Semantically incorrect message" },
 +      { GSM48_RR_CAUSE_INVALID_MAND_INF,      "Invalid mandatory information" },
 +      { GSM48_RR_CAUSE_MSG_TYPE_N,            "Message type non-existant or not implemented" },
 +      { GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT,     "Message type not compatible with protocol state" },
 +      { GSM48_RR_CAUSE_COND_IE_ERROR,         "Conditional IE error" },
 +      { GSM48_RR_CAUSE_NO_CELL_ALLOC_A,       "No cell allocation available" },
 +      { GSM48_RR_CAUSE_PROT_ERROR_UNSPC,      "Protocol error unspecified" },
 +      { 0,                                    NULL },
 +};
 +
 +/* FIXME: convert to value_string */
 +static const char *cc_state_names[32] = {
 +      "NULL",
 +      "INITIATED",
 +      "MM_CONNECTION_PEND",
 +      "MO_CALL_PROC",
 +      "CALL_DELIVERED",
 +      "illegal state 5",
 +      "CALL_PRESENT",
 +      "CALL_RECEIVED",
 +      "CONNECT_REQUEST",
 +      "MO_TERM_CALL_CONF",
 +      "ACTIVE",
 +      "DISCONNECT_REQ",
 +      "DISCONNECT_IND",
 +      "illegal state 13",
 +      "illegal state 14",
 +      "illegal state 15",
 +      "illegal state 16",
 +      "illegal state 17",
 +      "illegal state 18",
 +      "RELEASE_REQ",
 +      "illegal state 20",
 +      "illegal state 21",
 +      "illegal state 22",
 +      "illegal state 23",
 +      "illegal state 24",
 +      "illegal state 25",
 +      "MO_ORIG_MODIFY",
 +      "MO_TERM_MODIFY",
 +      "CONNECT_IND",
 +      "illegal state 29",
 +      "illegal state 30",
 +      "illegal state 31",
 +};
 +
 +const char *gsm48_cc_state_name(uint8_t state)
 +{
 +      if (state < ARRAY_SIZE(cc_state_names))
 +              return cc_state_names[state];
 +
 +      return "invalid";
 +}
 +
 +static const struct value_string cc_msg_names[] = {
 +      { GSM48_MT_CC_ALERTING,         "ALERTING" },
 +      { GSM48_MT_CC_CALL_PROC,        "CALL_PROC" },
 +      { GSM48_MT_CC_PROGRESS,         "PROGRESS" },
 +      { GSM48_MT_CC_ESTAB,            "ESTAB" },
 +      { GSM48_MT_CC_SETUP,            "SETUP" },
 +      { GSM48_MT_CC_ESTAB_CONF,       "ESTAB_CONF" },
 +      { GSM48_MT_CC_CONNECT,          "CONNECT" },
 +      { GSM48_MT_CC_CALL_CONF,        "CALL_CONF" },
 +      { GSM48_MT_CC_START_CC,         "START_CC" },
 +      { GSM48_MT_CC_RECALL,           "RECALL" },
 +      { GSM48_MT_CC_EMERG_SETUP,      "EMERG_SETUP" },
 +      { GSM48_MT_CC_CONNECT_ACK,      "CONNECT_ACK" },
 +      { GSM48_MT_CC_USER_INFO,        "USER_INFO" },
 +      { GSM48_MT_CC_MODIFY_REJECT,    "MODIFY_REJECT" },
 +      { GSM48_MT_CC_MODIFY,           "MODIFY" },
 +      { GSM48_MT_CC_HOLD,             "HOLD" },
 +      { GSM48_MT_CC_HOLD_ACK,         "HOLD_ACK" },
 +      { GSM48_MT_CC_HOLD_REJ,         "HOLD_REJ" },
 +      { GSM48_MT_CC_RETR,             "RETR" },
 +      { GSM48_MT_CC_RETR_ACK,         "RETR_ACK" },
 +      { GSM48_MT_CC_RETR_REJ,         "RETR_REJ" },
 +      { GSM48_MT_CC_MODIFY_COMPL,     "MODIFY_COMPL" },
 +      { GSM48_MT_CC_DISCONNECT,       "DISCONNECT" },
 +      { GSM48_MT_CC_RELEASE_COMPL,    "RELEASE_COMPL" },
 +      { GSM48_MT_CC_RELEASE,          "RELEASE" },
 +      { GSM48_MT_CC_STOP_DTMF,        "STOP_DTMF" },
 +      { GSM48_MT_CC_STOP_DTMF_ACK,    "STOP_DTMF_ACK" },
 +      { GSM48_MT_CC_STATUS_ENQ,       "STATUS_ENQ" },
 +      { GSM48_MT_CC_START_DTMF,       "START_DTMF" },
 +      { GSM48_MT_CC_START_DTMF_ACK,   "START_DTMF_ACK" },
 +      { GSM48_MT_CC_START_DTMF_REJ,   "START_DTMF_REJ" },
 +      { GSM48_MT_CC_CONG_CTRL,        "CONG_CTRL" },
 +      { GSM48_MT_CC_FACILITY,         "FACILITY" },
 +      { GSM48_MT_CC_STATUS,           "STATUS" },
 +      { GSM48_MT_CC_NOTIFY,           "NOTFIY" },
 +      { 0,                            NULL }
 +};
 +
 +const char *gsm48_cc_msg_name(uint8_t msgtype)
 +{
 +      return get_value_string(cc_msg_names, msgtype);
 +}
 +
 +const char *rr_cause_name(uint8_t cause)
 +{
 +      return get_value_string(rr_cause_names, cause);
 +}
 +
 +static void to_bcd(uint8_t *bcd, uint16_t val)
 +{
 +      bcd[2] = val % 10;
 +      val = val / 10;
 +      bcd[1] = val % 10;
 +      val = val / 10;
 +      bcd[0] = val % 10;
 +      val = val / 10;
 +}
 +
 +void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc,
 +                      uint16_t mnc, uint16_t lac)
 +{
 +      uint8_t bcd[3];
 +
 +      to_bcd(bcd, mcc);
 +      lai48->digits[0] = bcd[0] | (bcd[1] << 4);
 +      lai48->digits[1] = bcd[2];
 +
 +      to_bcd(bcd, mnc);
 +      /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
 +      if (mnc > 99) {
 +              lai48->digits[1] |= bcd[2] << 4;
 +              lai48->digits[2] = bcd[0] | (bcd[1] << 4);
 +      } else {
 +              lai48->digits[1] |= 0xf << 4;
 +              lai48->digits[2] = bcd[1] | (bcd[2] << 4);
 +      }
 +
 +      lai48->lac = htons(lac);
 +}
 +
 +int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi)
 +{
 +      uint32_t *tptr = (uint32_t *) &buf[3];
 +
 +      buf[0] = GSM48_IE_MOBILE_ID;
 +      buf[1] = GSM48_TMSI_LEN;
 +      buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
 +      *tptr = htonl(tmsi);
 +
 +      return 7;
 +}
 +
 +int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi)
 +{
 +      unsigned int length = strlen(imsi), i, off = 0;
 +      uint8_t odd = (length & 0x1) == 1;
 +
 +      buf[0] = GSM48_IE_MOBILE_ID;
-               lower = char2bcd(imsi[++off]);
++      buf[2] = osmo_char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3);
 +
 +      /* if the length is even we will fill half of the last octet */
 +      if (odd)
 +              buf[1] = (length + 1) >> 1;
 +      else
 +              buf[1] = (length + 2) >> 1;
 +
 +      for (i = 1; i < buf[1]; ++i) {
 +              uint8_t lower, upper;
 +
-                       upper = char2bcd(imsi[++off]) & 0x0f;
++              lower = osmo_char2bcd(imsi[++off]);
 +              if (!odd && off + 1 == length)
 +                      upper = 0x0f;
 +              else
-               *str_cur++ = bcd2char(mi[0] >> 4);
++                      upper = osmo_char2bcd(imsi[++off]) & 0x0f;
 +
 +              buf[2 + i] = (upper << 4) | lower;
 +      }
 +
 +      return 2 + buf[1];
 +}
 +
 +/* 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)
 +{
 +      int i;
 +      uint8_t mi_type;
 +      char *str_cur = string;
 +      uint32_t tmsi;
 +
 +      mi_type = mi[0] & GSM_MI_TYPE_MASK;
 +
 +      switch (mi_type) {
 +      case GSM_MI_TYPE_NONE:
 +              break;
 +      case GSM_MI_TYPE_TMSI:
 +              /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
 +              if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
 +                      memcpy(&tmsi, &mi[1], 4);
 +                      tmsi = ntohl(tmsi);
 +                      return snprintf(string, str_len, "%u", tmsi);
 +              }
 +              break;
 +      case GSM_MI_TYPE_IMSI:
 +      case GSM_MI_TYPE_IMEI:
 +      case GSM_MI_TYPE_IMEISV:
-                       *str_cur++ = bcd2char(mi[i] & 0xf);
++              *str_cur++ = osmo_bcd2char(mi[0] >> 4);
 +
 +                for (i = 1; i < mi_len; i++) {
 +                      if (str_cur + 2 >= string + str_len)
 +                              return str_cur - string;
-                               *str_cur++ = bcd2char(mi[i] >> 4);
++                      *str_cur++ = osmo_bcd2char(mi[i] & 0xf);
 +                      /* skip last nibble in last input byte when GSM_EVEN */
 +                      if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
++                              *str_cur++ = osmo_bcd2char(mi[i] >> 4);
 +              }
 +              break;
 +      default:
 +              break;
 +      }
 +      *str_cur++ = '\0';
 +
 +      return str_cur - string;
 +}
 +
 +void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf)
 +{
 +      raid->mcc = (buf[0] & 0xf) * 100;
 +      raid->mcc += (buf[0] >> 4) * 10;
 +      raid->mcc += (buf[1] & 0xf) * 1;
 +
 +      /* I wonder who came up with the stupidity of encoding the MNC
 +       * differently depending on how many digits its decimal number has! */
 +      if ((buf[1] >> 4) == 0xf) {
 +              raid->mnc = (buf[2] & 0xf) * 10;
 +              raid->mnc += (buf[2] >> 4) * 1;
 +      } else {
 +              raid->mnc = (buf[2] & 0xf) * 100;
 +              raid->mnc += (buf[2] >> 4) * 10;
 +              raid->mnc += (buf[1] >> 4) * 1;
 +      }
 +
 +      raid->lac = ntohs(*(uint16_t *)(buf + 3));
 +      raid->rac = buf[5];
 +}
 +
 +int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid)
 +{
 +      uint16_t mcc = raid->mcc;
 +      uint16_t mnc = raid->mnc;
 +
 +      buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4);
 +      buf[1] = (mcc % 10);
 +
 +      /* I wonder who came up with the stupidity of encoding the MNC
 +       * differently depending on how many digits its decimal number has! */
 +      if (mnc < 100) {
 +              buf[1] |= 0xf0;
 +              buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4);
 +      } else {
 +              buf[1] |= (mnc % 10) << 4;
 +              buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4);
 +      }
 +
 +      *(uint16_t *)(buf+3) = htons(raid->lac);
 +
 +      buf[5] = raid->rac;
 +
 +      return 6;
 +}
index 6d02d58,0000000..e0bc848
mode 100644,000000..100644
--- /dev/null
@@@ -1,200 -1,0 +1,253 @@@
- static struct bsc_fd gsmtap_bfd = { .fd = -1 };
 +/* GSMTAP output for Osmocom Layer2 (will only work on the host PC) */
 +/*
 + * (C) 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.
 + *
 + */
 +
 +#include "../config.h"
 +
 +#ifdef HAVE_SYS_SELECT_H
 +
 +#include <osmocom/core/gsmtap_util.h>
 +#include <osmocom/core/logging.h>
 +#include <osmocom/core/gsmtap.h>
 +#include <osmocom/core/msgb.h>
 +#include <osmocom/core/select.h>
 +#include <osmocom/gsm/protocol/gsm_04_08.h>
 +#include <osmocom/gsm/rsl.h>
 +
 +#include <arpa/inet.h>
 +#include <sys/socket.h>
 +#include <netinet/in.h>
 +
 +#include <stdio.h>
 +#include <unistd.h>
 +#include <stdint.h>
 +#include <string.h>
 +#include <errno.h>
 +
- static int gsmtap_fd_cb(struct bsc_fd *fd, unsigned int flags)
++static struct osmo_fd gsmtap_bfd = { .fd = -1 };
++static struct osmo_fd gsmtap_sink_bfd = { .fd = -1 };
 +static LLIST_HEAD(gsmtap_txqueue);
 +
 +uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
 +{
 +      uint8_t ret = GSMTAP_CHANNEL_UNKNOWN;
 +
 +      switch (rsl_chantype) {
 +      case RSL_CHAN_Bm_ACCHs:
 +              ret = GSMTAP_CHANNEL_TCH_F;
 +              break;
 +      case RSL_CHAN_Lm_ACCHs:
 +              ret = GSMTAP_CHANNEL_TCH_H;
 +              break;
 +      case RSL_CHAN_SDCCH4_ACCH:
 +              ret = GSMTAP_CHANNEL_SDCCH4;
 +              break;
 +      case RSL_CHAN_SDCCH8_ACCH:
 +              ret = GSMTAP_CHANNEL_SDCCH8;
 +              break;
 +      case RSL_CHAN_BCCH:
 +              ret = GSMTAP_CHANNEL_BCCH;
 +              break;
 +      case RSL_CHAN_RACH:
 +              ret = GSMTAP_CHANNEL_RACH;
 +              break;
 +      case RSL_CHAN_PCH_AGCH:
 +              /* it could also be AGCH... */
 +              ret = GSMTAP_CHANNEL_PCH;
 +              break;
 +      }
 +
 +      if (link_id & 0x40)
 +              ret |= GSMTAP_CHANNEL_ACCH;
 +
 +      return ret;
 +}
 +
 +/* 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)
 +{
 +      struct msgb *msg;
 +      struct gsmtap_hdr *gh;
 +      uint8_t *dst;
 +
 +      msg = msgb_alloc(sizeof(*gh) + len, "gsmtap_tx");
 +      if (!msg)
 +              return NULL;
 +
 +      gh = (struct gsmtap_hdr *) msgb_put(msg, sizeof(*gh));
 +
 +      gh->version = GSMTAP_VERSION;
 +      gh->hdr_len = sizeof(*gh)/4;
 +      gh->type = GSMTAP_TYPE_UM;
 +      gh->timeslot = ts;
 +      gh->sub_slot = ss;
 +      gh->arfcn = htons(arfcn);
 +      gh->snr_db = snr;
 +      gh->signal_dbm = signal_dbm;
 +      gh->frame_number = htonl(fn);
 +      gh->sub_type = chan_type;
 +      gh->antenna_nr = 0;
 +
 +      dst = msgb_put(msg, len);
 +      memcpy(dst, data, len);
 +
 +      return msg;
 +}
 +
 +/* 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)
 +{
 +      struct msgb *msg;
 +
 +      /* gsmtap was never initialized, so don't try to send anything */
 +      if (gsmtap_bfd.fd == -1)
 +              return 0;
 +
 +      msg = gsmtap_makemsg(arfcn, ts, chan_type, ss, fn, signal_dbm,
 +                           snr, data, len);
 +      if (!msg)
 +              return -ENOMEM;
 +
 +      msgb_enqueue(&gsmtap_txqueue, msg);
 +      gsmtap_bfd.when |= BSC_FD_WRITE;
 +
 +      return 0;
 +}
 +
 +/* Callback from select layer if we can write to the socket */
-       /* FIXME: create socket */
++static int gsmtap_fd_cb(struct osmo_fd *fd, unsigned int flags)
 +{
 +      struct msgb *msg;
 +      int rc;
 +
 +      if (!(flags & BSC_FD_WRITE))
 +              return 0;
 +
 +      msg = msgb_dequeue(&gsmtap_txqueue);
 +      if (!msg) {
 +              /* no more messages in the queue, disable READ cb */
 +              gsmtap_bfd.when = 0;
 +              return 0;
 +      }
 +      rc = write(gsmtap_bfd.fd, msg->data, msg->len);
 +      if (rc < 0) {
 +              perror("writing msgb to gsmtap fd");
 +              msgb_free(msg);
 +              return rc;
 +      }
 +      if (rc != msg->len) {
 +              perror("short write to gsmtap fd");
 +              msgb_free(msg);
 +              return -EIO;
 +      }
 +
 +      msgb_free(msg);
 +      return 0;
 +}
 +
 +int gsmtap_init(uint32_t dst_ip)
 +{
 +      int rc;
 +      struct sockaddr_in sin;
 +
 +      sin.sin_family = AF_INET;
 +      sin.sin_port = htons(GSMTAP_UDP_PORT);
 +      sin.sin_addr.s_addr = htonl(dst_ip);
 +
-               gsmtap_bfd.fd = 0;
++      /* create socket */
 +      rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 +      if (rc < 0) {
 +              perror("creating UDP socket");
 +              return rc;
 +      }
 +      gsmtap_bfd.fd = rc;
 +      rc = connect(rc, (struct sockaddr *)&sin, sizeof(sin));
 +      if (rc < 0) {
 +              perror("connecting UDP socket");
 +              close(gsmtap_bfd.fd);
-       return bsc_register_fd(&gsmtap_bfd);
++              gsmtap_bfd.fd = -1;
 +              return rc;
 +      }
 +
 +      gsmtap_bfd.when = BSC_FD_WRITE;
 +      gsmtap_bfd.cb = gsmtap_fd_cb;
 +      gsmtap_bfd.data = NULL;
 +
++      return osmo_fd_register(&gsmtap_bfd);
++}
++
++/* Callback from select layer if we can read from the sink socket */
++static int gsmtap_sink_fd_cb(struct osmo_fd *fd, unsigned int flags)
++{
++      int rc;
++      uint8_t buf[4096];
++
++      if (!(flags & BSC_FD_READ))
++              return 0;
++
++      rc = read(fd->fd, buf, sizeof(buf));
++      if (rc < 0) {
++              perror("reading from gsmtap sink fd");
++              return rc;
++      }
++      /* simply discard any data arriving on the socket */
++
++      return 0;
++}
++
++/* Create a local 'gsmtap sink' avoiding the UDP packets being rejected
++ * with ICMP reject messages */
++int gsmtap_sink_init(uint32_t bind_ip)
++{
++      int rc;
++      struct sockaddr_in sin;
++
++      sin.sin_family = AF_INET;
++      sin.sin_port = htons(GSMTAP_UDP_PORT);
++      sin.sin_addr.s_addr = htonl(bind_ip);
++
++      rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
++      if (rc < 0) {
++              perror("creating UDP socket");
++              return rc;
++      }
++      gsmtap_sink_bfd.fd = rc;
++      rc = bind(rc, (struct sockaddr *)&sin, sizeof(sin));
++      if (rc < 0) {
++              perror("binding UDP socket");
++              close(gsmtap_sink_bfd.fd);
++              gsmtap_sink_bfd.fd = -1;
++              return rc;
++      }
++
++      gsmtap_sink_bfd.when = BSC_FD_READ;
++      gsmtap_sink_bfd.cb = gsmtap_sink_fd_cb;
++      gsmtap_sink_bfd.data = NULL;
++
++      return osmo_fd_register(&gsmtap_sink_bfd);
++
 +}
 +
 +#endif /* HAVE_SYS_SELECT_H */
index 77c8a50,0000000..0911010
mode 100644,000000..100644
--- /dev/null
@@@ -1,553 -1,0 +1,556 @@@
-       char col[30];
-       char sub[30];
-       char tim[30];
 +/* Debugging/Logging support code */
 +
 +/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
 + * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include "../config.h"
 +
 +#include <stdarg.h>
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <ctype.h>
 +
 +#ifdef HAVE_STRINGS_H
 +#include <strings.h>
 +#endif
 +#include <time.h>
 +#include <errno.h>
 +
 +#include <osmocom/core/talloc.h>
 +#include <osmocom/core/utils.h>
 +#include <osmocom/core/logging.h>
 +
 +#include <osmocom/vty/logging.h>      /* for LOGGING_STR. */
 +
 +const struct log_info *osmo_log_info;
 +
 +static struct log_context log_context;
 +static void *tall_log_ctx = NULL;
 +LLIST_HEAD(osmo_log_target_list);
 +
 +#define LOGLEVEL_DEFS 6       /* Number of loglevels.*/
 +
 +static const struct value_string loglevel_strs[LOGLEVEL_DEFS+1] = {
 +      { 0,            "EVERYTHING" },
 +      { LOGL_DEBUG,   "DEBUG" },
 +      { LOGL_INFO,    "INFO" },
 +      { LOGL_NOTICE,  "NOTICE" },
 +      { LOGL_ERROR,   "ERROR" },
 +      { LOGL_FATAL,   "FATAL" },
 +      { 0, NULL },
 +};
 +
 +/* You have to keep this in sync with the structure loglevel_strs. */
 +const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
 +      "Log simply everything",
 +      "Log debug messages and higher levels",
 +      "Log informational messages and higher levels",
 +      "Log noticable messages and higher levels",
 +      "Log error messages and higher levels",
 +      "Log only fatal messages",
 +      NULL,
 +};
 +
 +int log_parse_level(const char *lvl)
 +{
 +      return get_string_value(loglevel_strs, lvl);
 +}
 +
 +const char *log_level_str(unsigned int lvl)
 +{
 +      return get_value_string(loglevel_strs, lvl);
 +}
 +
 +int log_parse_category(const char *category)
 +{
 +      int i;
 +
 +      for (i = 0; i < osmo_log_info->num_cat; ++i) {
 +              if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
 +                      return i;
 +      }
 +
 +      return -EINVAL;
 +}
 +
 +/*
 + * Parse the category mask.
 + * The format can be this: category1:category2:category3
 + * or category1,2:category2,3:...
 + */
 +void log_parse_category_mask(struct log_target* target, const char *_mask)
 +{
 +      int i = 0;
 +      char *mask = strdup(_mask);
 +      char *category_token = NULL;
 +
 +      /* Disable everything to enable it afterwards */
 +      for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
 +              target->categories[i].enabled = 0;
 +
 +      category_token = strtok(mask, ":");
 +      do {
 +              for (i = 0; i < osmo_log_info->num_cat; ++i) {
 +                      char* colon = strstr(category_token, ",");
 +                      int length = strlen(category_token);
 +
 +                      if (colon)
 +                          length = colon - category_token;
 +
 +                      if (strncasecmp(osmo_log_info->cat[i].name,
 +                                      category_token, length) == 0) {
 +                              int level = 0;
 +
 +                              if (colon)
 +                                      level = atoi(colon+1);
 +
 +                              target->categories[i].enabled = 1;
 +                              target->categories[i].loglevel = level;
 +                      }
 +              }
 +      } while ((category_token = strtok(NULL, ":")));
 +
 +      free(mask);
 +}
 +
 +static const char* color(int subsys)
 +{
 +      if (subsys < osmo_log_info->num_cat)
 +              return osmo_log_info->cat[subsys].color;
 +
 +      return NULL;
 +}
 +
 +static void _output(struct log_target *target, unsigned int subsys,
 +                  unsigned int level, char *file, int line, int cont,
 +                  const char *format, va_list ap)
 +{
-       char final[4096];
-       /* prepare the data */
-       col[0] = '\0';
-       sub[0] = '\0';
-       tim[0] = '\0';
-       buf[0] = '\0';
 +      char buf[4096];
-                       snprintf(col, sizeof(col), "%s", color(subsys));
-                       col[sizeof(col)-1] = '\0';
++      int ret, len = 0, offset = 0, rem = sizeof(buf);
 +
 +      /* are we using color */
 +      if (target->use_color) {
 +              const char *c = color(subsys);
 +              if (c) {
-       vsnprintf(buf, sizeof(buf), format, ap);
-       buf[sizeof(buf)-1] = '\0';
++                      ret = snprintf(buf + offset, rem, "%s", color(subsys));
++                      if (ret < 0)
++                              goto err;
++                      OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +              }
 +      }
-                       snprintf(tim, sizeof(tim), "%s ", timestr);
-                       tim[sizeof(tim)-1] = '\0';
 +      if (!cont) {
 +              if (target->print_timestamp) {
 +                      char *timestr;
 +                      time_t tm;
 +                      tm = time(NULL);
 +                      timestr = ctime(&tm);
 +                      timestr[strlen(timestr)-1] = '\0';
-               snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line);
-               sub[sizeof(sub)-1] = '\0';
++                      ret = snprintf(buf + offset, rem, "%s ", timestr);
++                      if (ret < 0)
++                              goto err;
++                      OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +              }
-       snprintf(final, sizeof(final), "%s%s%s%s%s", col, tim, sub, buf,
-                target->use_color ? "\033[0;m" : "");
-       final[sizeof(final)-1] = '\0';
-       target->output(target, level, final);
++              ret = snprintf(buf + offset, rem, "<%4.4x> %s:%d ",
++                              subsys, file, line);
++              if (ret < 0)
++                      goto err;
++              OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +      }
++      ret = vsnprintf(buf + offset, rem, format, ap);
++      if (ret < 0)
++              goto err;
++      OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +
-               if (output) {
-                       /* FIXME: copying the va_list is an ugly
-                        * workaround against a bug hidden somewhere in
-                        * _output.  If we do not copy here, the first
-                        * call to _output() will corrupt the va_list
-                        * contents, and any further _output() calls
-                        * with the same va_list will segfault */
-                       va_list bp;
-                       va_copy(bp, ap);
-                       _output(tar, subsys, level, file, line, cont, format, bp);
-                       va_end(bp);
-               }
++      ret = snprintf(buf + offset, rem, "%s",
++                      target->use_color ? "\033[0;m" : "");
++      if (ret < 0)
++              goto err;
++      OSMO_SNPRINTF_RET(ret, rem, offset, len);
++err:
++      buf[sizeof(buf)-1] = '\0';
++      target->output(target, level, buf);
 +}
 +
 +
 +static void _logp(unsigned int subsys, int level, char *file, int line,
 +                int cont, const char *format, va_list ap)
 +{
 +      struct log_target *tar;
 +
 +      llist_for_each_entry(tar, &osmo_log_target_list, entry) {
 +              struct log_category *category;
 +              int output = 0;
 +
 +              category = &tar->categories[subsys];
 +              /* subsystem is not supposed to be logged */
 +              if (!category->enabled)
 +                      continue;
 +
 +              /* Check the global log level */
 +              if (tar->loglevel != 0 && level < tar->loglevel)
 +                      continue;
 +
 +              /* Check the category log level */
 +              if (tar->loglevel == 0 && category->loglevel != 0 &&
 +                  level < category->loglevel)
 +                      continue;
 +
 +              /* Apply filters here... if that becomes messy we will
 +               * need to put filters in a list and each filter will
 +               * say stop, continue, output */
 +              if ((tar->filter_map & LOG_FILTER_ALL) != 0)
 +                      output = 1;
 +              else if (osmo_log_info->filter_fn)
 +                      output = osmo_log_info->filter_fn(&log_context,
 +                                                     tar);
++              if (!output)
++                      continue;
 +
-       str = talloc_zero_size(NULL, size);
++              _output(tar, subsys, level, file, line, cont, format, ap);
 +      }
 +}
 +
 +void logp(unsigned int subsys, char *file, int line, int cont,
 +        const char *format, ...)
 +{
 +      va_list ap;
 +
 +      va_start(ap, format);
 +      _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
 +      va_end(ap);
 +}
 +
 +void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
 +{
 +      va_list ap;
 +
 +      va_start(ap, format);
 +      _logp(subsys, level, file, line, cont, format, ap);
 +      va_end(ap);
 +}
 +
 +void log_add_target(struct log_target *target)
 +{
 +      llist_add_tail(&target->entry, &osmo_log_target_list);
 +}
 +
 +void log_del_target(struct log_target *target)
 +{
 +      llist_del(&target->entry);
 +}
 +
 +void log_reset_context(void)
 +{
 +      memset(&log_context, 0, sizeof(log_context));
 +}
 +
 +int log_set_context(uint8_t ctx_nr, void *value)
 +{
 +      if (ctx_nr > LOG_MAX_CTX)
 +              return -EINVAL;
 +
 +      log_context.ctx[ctx_nr] = value;
 +
 +      return 0;
 +}
 +
 +void log_set_all_filter(struct log_target *target, int all)
 +{
 +      if (all)
 +              target->filter_map |= LOG_FILTER_ALL;
 +      else
 +              target->filter_map &= ~LOG_FILTER_ALL;
 +}
 +
 +void log_set_use_color(struct log_target *target, int use_color)
 +{
 +      target->use_color = use_color;
 +}
 +
 +void log_set_print_timestamp(struct log_target *target, int print_timestamp)
 +{
 +      target->print_timestamp = print_timestamp;
 +}
 +
 +void log_set_log_level(struct log_target *target, int log_level)
 +{
 +      target->loglevel = log_level;
 +}
 +
 +void log_set_category_filter(struct log_target *target, int category,
 +                             int enable, int level)
 +{
 +      if (category >= osmo_log_info->num_cat)
 +              return;
 +      target->categories[category].enabled = !!enable;
 +      target->categories[category].loglevel = level;
 +}
 +
 +static void _file_output(struct log_target *target, unsigned int level,
 +                       const char *log)
 +{
 +      fprintf(target->tgt_file.out, "%s", log);
 +      fflush(target->tgt_file.out);
 +}
 +
 +struct log_target *log_target_create(void)
 +{
 +      struct log_target *target;
 +      unsigned int i;
 +
 +      target = talloc_zero(tall_log_ctx, struct log_target);
 +      if (!target)
 +              return NULL;
 +
 +      INIT_LLIST_HEAD(&target->entry);
 +
 +      /* initialize the per-category enabled/loglevel from defaults */
 +      for (i = 0; i < osmo_log_info->num_cat; i++) {
 +              struct log_category *cat = &target->categories[i];
 +              cat->enabled = osmo_log_info->cat[i].enabled;
 +              cat->loglevel = osmo_log_info->cat[i].loglevel;
 +      }
 +
 +      /* global settings */
 +      target->use_color = 1;
 +      target->print_timestamp = 0;
 +
 +      /* global log level */
 +      target->loglevel = 0;
 +      return target;
 +}
 +
 +struct log_target *log_target_create_stderr(void)
 +{
 +/* since C89/C99 says stderr is a macro, we can safely do this! */
 +#ifdef stderr
 +      struct log_target *target;
 +
 +      target = log_target_create();
 +      if (!target)
 +              return NULL;
 +
 +      target->type = LOG_TGT_TYPE_STDERR;
 +      target->tgt_file.out = stderr;
 +      target->output = _file_output;
 +      return target;
 +#else
 +      return NULL;
 +#endif /* stderr */
 +}
 +
 +struct log_target *log_target_create_file(const char *fname)
 +{
 +      struct log_target *target;
 +
 +      target = log_target_create();
 +      if (!target)
 +              return NULL;
 +
 +      target->type = LOG_TGT_TYPE_FILE;
 +      target->tgt_file.out = fopen(fname, "a");
 +      if (!target->tgt_file.out)
 +              return NULL;
 +
 +      target->output = _file_output;
 +
 +      target->tgt_file.fname = talloc_strdup(target, fname);
 +
 +      return target;
 +}
 +
 +struct log_target *log_target_find(int type, const char *fname)
 +{
 +      struct log_target *tgt;
 +
 +      llist_for_each_entry(tgt, &osmo_log_target_list, entry) {
 +              if (tgt->type != type)
 +                      continue;
 +              if (tgt->type == LOG_TGT_TYPE_FILE) {
 +                      if (!strcmp(fname, tgt->tgt_file.fname))
 +                              return tgt;
 +              } else
 +                      return tgt;
 +      }
 +      return NULL;
 +}
 +
 +void log_target_destroy(struct log_target *target)
 +{
 +
 +      /* just in case, to make sure we don't have any references */
 +      log_del_target(target);
 +
 +      if (target->output == &_file_output) {
 +/* since C89/C99 says stderr is a macro, we can safely do this! */
 +#ifdef stderr
 +              /* don't close stderr */
 +              if (target->tgt_file.out != stderr)
 +#endif
 +              {
 +                      fclose(target->tgt_file.out);
 +                      target->tgt_file.out = NULL;
 +              }
 +      }
 +
 +      talloc_free(target);
 +}
 +
 +/* close and re-open a log file (for log file rotation) */
 +int log_target_file_reopen(struct log_target *target)
 +{
 +      fclose(target->tgt_file.out);
 +
 +      target->tgt_file.out = fopen(target->tgt_file.fname, "a");
 +      if (!target->tgt_file.out)
 +              return -errno;
 +
 +      /* we assume target->output already to be set */
 +
 +      return 0;
 +}
 +
 +/* This generates the logging command string for VTY. */
 +const char *log_vty_command_string(const struct log_info *info)
 +{
 +      int len = 0, offset = 0, ret, i, rem;
 +      int size = strlen("logging level () ()") + 1;
 +      char *str;
 +
 +      for (i = 0; i < info->num_cat; i++)
 +              size += strlen(info->cat[i].name) + 1;
 +
 +      for (i = 0; i < LOGLEVEL_DEFS; i++)
 +              size += strlen(loglevel_strs[i].str) + 1;
 +
 +      rem = size;
-       str = talloc_zero_size(NULL, size);
++      str = talloc_zero_size(tall_log_ctx, size);
 +      if (!str)
 +              return NULL;
 +
 +      ret = snprintf(str + offset, rem, "logging level (all|");
 +      if (ret < 0)
 +              goto err;
 +      OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +
 +      for (i = 0; i < info->num_cat; i++) {
 +              int j, name_len = strlen(info->cat[i].name)+1;
 +              char name[name_len];
 +
 +              for (j = 0; j < name_len; j++)
 +                      name[j] = tolower(info->cat[i].name[j]);
 +
 +              name[name_len-1] = '\0';
 +              ret = snprintf(str + offset, rem, "%s|", name+1);
 +              if (ret < 0)
 +                      goto err;
 +              OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +      }
 +      offset--;       /* to remove the trailing | */
 +      rem++;
 +
 +      ret = snprintf(str + offset, rem, ") (");
 +      if (ret < 0)
 +              goto err;
 +      OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +
 +      for (i = 0; i < LOGLEVEL_DEFS; i++) {
 +              int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
 +              char loglevel_str[loglevel_str_len];
 +
 +              for (j = 0; j < loglevel_str_len; j++)
 +                      loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
 +
 +              loglevel_str[loglevel_str_len-1] = '\0';
 +              ret = snprintf(str + offset, rem, "%s|", loglevel_str);
 +              if (ret < 0)
 +                      goto err;
 +              OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +      }
 +      offset--;       /* to remove the trailing | */
 +      rem++;
 +
 +      ret = snprintf(str + offset, rem, ")");
 +      if (ret < 0)
 +              goto err;
 +      OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +err:
++      str[size-1] = '\0';
 +      return str;
 +}
 +
 +/* This generates the logging command description for VTY. */
 +const char *log_vty_command_description(const struct log_info *info)
 +{
 +      char *str;
 +      int i, ret, len = 0, offset = 0, rem;
 +      unsigned int size =
 +              strlen(LOGGING_STR
 +                     "Set the log level for a specified category\n") + 1;
 +
 +      for (i = 0; i < info->num_cat; i++)
 +              size += strlen(info->cat[i].description) + 1;
 +
 +      for (i = 0; i < LOGLEVEL_DEFS; i++)
 +              size += strlen(loglevel_descriptions[i]) + 1;
 +
++      size += strlen("Global setting for all subsystems") + 1;
 +      rem = size;
++      str = talloc_zero_size(tall_log_ctx, size);
 +      if (!str)
 +              return NULL;
 +
 +      ret = snprintf(str + offset, rem, LOGGING_STR
 +                      "Set the log level for a specified category\n");
 +      if (ret < 0)
 +              goto err;
 +      OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +
++      ret = snprintf(str + offset, rem,
++                      "Global setting for all subsystems\n");
++      if (ret < 0)
++              goto err;
++      OSMO_SNPRINTF_RET(ret, rem, offset, len);
++
 +      for (i = 0; i < info->num_cat; i++) {
 +              ret = snprintf(str + offset, rem, "%s\n",
 +                              info->cat[i].description);
 +              if (ret < 0)
 +                      goto err;
 +              OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +      }
 +      for (i = 0; i < LOGLEVEL_DEFS; i++) {
 +              ret = snprintf(str + offset, rem, "%s\n",
 +                              loglevel_descriptions[i]);
 +              if (ret < 0)
 +                      goto err;
 +              OSMO_SNPRINTF_RET(ret, rem, offset, len);
 +      }
 +err:
++      str[size-1] = '\0';
 +      return str;
 +}
 +
 +void log_init(const struct log_info *cat)
 +{
 +      tall_log_ctx = talloc_named_const(NULL, 1, "logging");
 +      osmo_log_info = cat;
 +}
index c13df51,0000000..d2b180d
mode 100644,000000..100644
--- /dev/null
@@@ -1,121 -1,0 +1,123 @@@
- static struct msg_entry *alloc_entry(struct msg_entries *entries,
-                                    const char *mcc, const char *mnc,
-                                    const char *option, const char *text)
 +/*
 + * Parse a simple file with messages, e.g used for USSD messages
 + *
 + * (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.
 + *
 + */
 +
 +#include <osmocom/core/msgfile.h>
 +#include <osmocom/core/talloc.h>
 +
 +#include <sys/stat.h>
 +#include <fcntl.h>
 +#include <unistd.h>
 +#include <string.h>
 +
-       struct msg_entry *entry = talloc_zero(entries, struct msg_entry);
++static struct osmo_config_entry *
++alloc_entry(struct osmo_config_list *entries,
++          const char *mcc, const char *mnc,
++          const char *option, const char *text)
 +{
- static struct msg_entries *alloc_entries(void *ctx)
++      struct osmo_config_entry *entry =
++              talloc_zero(entries, struct osmo_config_entry);
 +      if (!entry)
 +              return NULL;
 +
 +      entry->mcc = talloc_strdup(entry, mcc);
 +      entry->mnc = talloc_strdup(entry, mnc);
 +      entry->option = talloc_strdup(entry, option);
 +      entry->text = talloc_strdup(entry, text);
 +
 +      llist_add_tail(&entry->list, &entries->entry);
 +      return entry;
 +}
 +
-       struct msg_entries *entries;
++static struct osmo_config_list *alloc_entries(void *ctx)
 +{
-       entries = talloc_zero(ctx, struct msg_entries);
++      struct osmo_config_list *entries;
 +
- static void handle_line(struct msg_entries *entries, char *line)
++      entries = talloc_zero(ctx, struct osmo_config_list);
 +      if (!entries)
 +              return NULL;
 +
 +      INIT_LLIST_HEAD(&entries->entry);
 +      return entries;
 +}
 +
 +/*
 + * split a line like 'foo:Text'.
 + */
- struct msg_entries *msg_entry_parse(void *ctx, const char *filename)
++static void handle_line(struct osmo_config_list *entries, char *line)
 +{
 +      int i;
 +      const int len = strlen(line);
 +
 +      char *items[3];
 +      int last_item = 0;
 +
 +      /* Skip comments from the file */
 +      if (line[0] == '#')
 +              return;
 +
 +      for (i = 0; i < len; ++i) {
 +              if (line[i] == '\n' || line[i] == '\r')
 +                      line[i] = '\0';
 +              else if (line[i] == ':' && last_item < 3) {
 +                      line[i] = '\0';
 +
 +                      items[last_item++] = &line[i + 1];
 +              }
 +      }
 +
 +      if (last_item == 3) {
 +              alloc_entry(entries, &line[0] , items[0], items[1], items[2]);
 +              return;
 +      }
 +
 +      /* nothing found */
 +}
 +
-       struct msg_entries *entries;
++struct osmo_config_list *osmo_config_list_parse(void *ctx, const char *filename)
 +{
++      struct osmo_config_list *entries;
 +      size_t n;
 +      char *line;
 +      FILE *file;
 +
 +      file = fopen(filename, "r");
 +      if (!file)
 +              return NULL;
 +
 +      entries = alloc_entries(ctx);
 +      if (!entries) {
 +              fclose(file);
 +              return NULL;
 +      }
 +
 +      n = 2342;
 +      line = NULL;
 +        while (getline(&line, &n, file) != -1) {
 +              handle_line(entries, line);
 +              free(line);
 +              line = NULL;
 +      }
 +
 +      fclose(file);
 +      return entries;
 +}
index 588a5fe,0000000..d445226
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,74 @@@
-       generate_backtrace();
 +/* Panic handling */
 +/*
 + * (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <osmocom/gsm/gsm_utils.h>
 +#include <osmocom/core/panic.h>
 +#include <osmocom/core/backtrace.h>
 +
 +#include "../config.h"
 +
 +
 +static osmo_panic_handler_t osmo_panic_handler = (void*)0;
 +
 +
 +#ifndef PANIC_INFLOOP
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +
 +static void osmo_panic_default(const char *fmt, va_list args)
 +{
 +      vfprintf(stderr, fmt, args);
++      osmo_generate_backtrace();
 +      abort();
 +}
 +
 +#else
 +
 +static void osmo_panic_default(const char *fmt, va_list args)
 +{
 +      while (1);
 +}
 +
 +#endif
 +
 +
 +void osmo_panic(const char *fmt, ...)
 +{
 +      va_list args;
 +
 +      va_start(args, fmt);
 +
 +      if (osmo_panic_handler)
 +              osmo_panic_handler(fmt, args);
 +      else
 +              osmo_panic_default(fmt, args);
 +
 +      va_end(args);
 +}
 + 
 +
 +void osmo_set_panic_handler(osmo_panic_handler_t h)
 +{
 +      osmo_panic_handler = h;
 +}
 +
index 4d9fd31,0000000..998bca3
mode 100644,000000..100644
--- /dev/null
@@@ -1,62 -1,0 +1,62 @@@
- int plugin_load_all(const char *directory)
 +/* plugin infrastructure */
 +
 +/* (C) 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.
 + *
 + */
 +
 +#include "../config.h"
 +
 +#if HAVE_DLFCN_H
 +
 +#include <dirent.h>
 +#include <dlfcn.h>
 +#include <stdio.h>
 +#include <errno.h>
 +#include <limits.h>
 +
 +#include <osmocom/core/plugin.h>
 +
- int plugin_load_all(const char *directory)
++int osmo_plugin_load_all(const char *directory)
 +{
 +      unsigned int num = 0;
 +      char fname[PATH_MAX];
 +      DIR *dir;
 +      struct dirent *entry;
 +
 +      dir = opendir(directory);
 +      if (!dir)
 +              return -errno;
 +
 +      while ((entry = readdir(dir))) {
 +              snprintf(fname, sizeof(fname), "%s/%s", directory,
 +                      entry->d_name);
 +              if (dlopen(fname, RTLD_NOW))
 +                      num++;
 +      }
 +
 +      closedir(dir);
 +
 +      return num;
 +}
 +#else
++int osmo_plugin_load_all(const char *directory)
 +{
 +      return 0;
 +}
 +#endif /* HAVE_DLFCN_H */
index a0e1814,0000000..6d771a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,161 -1,0 +1,161 @@@
- static struct timer_list rate_ctr_timer;
 +/* utility routines for keeping conters about events and the event rates */
 +
 +/* (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.
 + *
 + */
 +
 +#include <stdint.h>
 +#include <string.h>
 +
 +#include <osmocom/core/utils.h>
 +#include <osmocom/core/linuxlist.h>
 +#include <osmocom/core/talloc.h>
 +#include <osmocom/core/timer.h>
 +#include <osmocom/core/rate_ctr.h>
 +
 +static LLIST_HEAD(rate_ctr_groups);
 +
 +static void *tall_rate_ctr_ctx;
 +
 +struct rate_ctr_group *rate_ctr_group_alloc(void *ctx,
 +                                          const struct rate_ctr_group_desc *desc,
 +                                          unsigned int idx)
 +{
 +      unsigned int size;
 +      struct rate_ctr_group *group;
 +
 +      size = sizeof(struct rate_ctr_group) +
 +                      desc->num_ctr * sizeof(struct rate_ctr);
 +
 +      if (!ctx)
 +              ctx = tall_rate_ctr_ctx;
 +
 +      group = talloc_zero_size(ctx, size);
 +      if (!group)
 +              return NULL;
 +
 +      group->desc = desc;
 +      group->idx = idx;
 +
 +      llist_add(&group->list, &rate_ctr_groups);
 +
 +      return group;
 +}
 +
 +void rate_ctr_group_free(struct rate_ctr_group *grp)
 +{
 +      llist_del(&grp->list);
 +      talloc_free(grp);
 +}
 +
 +void rate_ctr_add(struct rate_ctr *ctr, int inc)
 +{
 +      ctr->current += inc;
 +}
 +
 +static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv)
 +{
 +      /* calculate rate over last interval */
 +      ctr->intv[intv].rate = ctr->current - ctr->intv[intv].last;
 +      /* save current counter for next interval */
 +      ctr->intv[intv].last = ctr->current;
 +
 +      /* update the rate of the next bigger interval.  This will
 +       * be overwritten when that next larger interval expires */
 +      if (intv + 1 < ARRAY_SIZE(ctr->intv))
 +              ctr->intv[intv+1].rate += ctr->intv[intv].rate;
 +}
 +
-       bsc_schedule_timer(&rate_ctr_timer, 1, 0);
++static struct osmo_timer_list rate_ctr_timer;
 +static uint64_t timer_ticks;
 +
 +/* The one-second interval has expired */
 +static void rate_ctr_group_intv(struct rate_ctr_group *grp)
 +{
 +      unsigned int i;
 +
 +      for (i = 0; i < grp->desc->num_ctr; i++) {
 +              struct rate_ctr *ctr = &grp->ctr[i];
 +
 +              interval_expired(ctr, RATE_CTR_INTV_SEC);
 +              if ((timer_ticks % 60) == 0)
 +                      interval_expired(ctr, RATE_CTR_INTV_MIN);
 +              if ((timer_ticks % (60*60)) == 0)
 +                      interval_expired(ctr, RATE_CTR_INTV_HOUR);
 +              if ((timer_ticks % (24*60*60)) == 0)
 +                      interval_expired(ctr, RATE_CTR_INTV_DAY);
 +      }
 +}
 +
 +static void rate_ctr_timer_cb(void *data)
 +{
 +      struct rate_ctr_group *ctrg;
 +
 +      /* Increment number of ticks before we calculate intervals,
 +       * as a counter value of 0 would already wrap all counters */
 +      timer_ticks++;
 +
 +      llist_for_each_entry(ctrg, &rate_ctr_groups, list)
 +              rate_ctr_group_intv(ctrg);
 +
-       bsc_schedule_timer(&rate_ctr_timer, 1, 0);
++      osmo_timer_schedule(&rate_ctr_timer, 1, 0);
 +}
 +
 +int rate_ctr_init(void *tall_ctx)
 +{
 +      tall_rate_ctr_ctx = tall_ctx;
 +      rate_ctr_timer.cb = rate_ctr_timer_cb;
++      osmo_timer_schedule(&rate_ctr_timer, 1, 0);
 +
 +      return 0;
 +}
 +
 +struct rate_ctr_group *rate_ctr_get_group_by_name_idx(const char *name, const unsigned int idx)
 +{
 +      struct rate_ctr_group *ctrg;
 +
 +      llist_for_each_entry(ctrg, &rate_ctr_groups, list) {
 +              if (!ctrg->desc)
 +                      continue;
 +
 +              if (!strcmp(ctrg->desc->group_name_prefix, name) &&
 +                              ctrg->idx == idx) {
 +                      return ctrg;
 +              }
 +      }
 +      return NULL;
 +}
 +
 +const struct rate_ctr *rate_ctr_get_by_name(const struct rate_ctr_group *ctrg, const char *name)
 +{
 +      int i;
 +      const struct rate_ctr_desc *ctr_desc;
 +
 +      if (!ctrg->desc)
 +              return NULL;
 +
 +      for (i = 0; i < ctrg->desc->num_ctr; i++) {
 +              ctr_desc = &ctrg->desc->ctr_desc[i];
 +
 +              if (!strcmp(ctr_desc->name, name)) {
 +                      return &ctrg->ctr[i];
 +              }
 +      }
 +      return NULL;
 +}
index adf3619,0000000..4ea9536
mode 100644,000000..100644
--- /dev/null
@@@ -1,144 -1,0 +1,144 @@@
- static LLIST_HEAD(bsc_fds);
 +/* select filedescriptor handling, taken from:
 + * userspace logging daemon for the iptables ULOG target
 + * of the linux 2.4 netfilter subsystem.
 + *
 + * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org>
 + *
 + *  This program is free software; you can redistribute it and/or modify
 + *  it under the terms of the GNU General Public License 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 + */
 +
 +#include <fcntl.h>
 +#include <stdio.h>
 +
 +#include <osmocom/core/select.h>
 +#include <osmocom/core/linuxlist.h>
 +#include <osmocom/core/timer.h>
 +
 +#include "../config.h"
 +
 +#ifdef HAVE_SYS_SELECT_H
 +
 +static int maxfd = 0;
- int bsc_register_fd(struct bsc_fd *fd)
++static LLIST_HEAD(osmo_fds);
 +static int unregistered_count;
 +
-       struct bsc_fd *entry;
-       llist_for_each_entry(entry, &bsc_fds, list) {
++int osmo_fd_register(struct osmo_fd *fd)
 +{
 +      int flags;
 +
 +      /* make FD nonblocking */
 +      flags = fcntl(fd->fd, F_GETFL);
 +      if (flags < 0)
 +              return flags;
 +      flags |= O_NONBLOCK;
 +      flags = fcntl(fd->fd, F_SETFL, flags);
 +      if (flags < 0)
 +              return flags;
 +
 +      /* Register FD */
 +      if (fd->fd > maxfd)
 +              maxfd = fd->fd;
 +
 +#ifdef BSC_FD_CHECK
-                       fprintf(stderr, "Adding a bsc_fd that is already in the list.\n");
++      struct osmo_fd *entry;
++      llist_for_each_entry(entry, &osmo_fds, list) {
 +              if (entry == fd) {
-       llist_add_tail(&fd->list, &bsc_fds);
++                      fprintf(stderr, "Adding a osmo_fd that is already in the list.\n");
 +                      return 0;
 +              }
 +      }
 +#endif
 +
- void bsc_unregister_fd(struct bsc_fd *fd)
++      llist_add_tail(&fd->list, &osmo_fds);
 +
 +      return 0;
 +}
 +
- int bsc_select_main(int polling)
++void osmo_fd_unregister(struct osmo_fd *fd)
 +{
 +      unregistered_count++;
 +      llist_del(&fd->list);
 +}
 +
-       struct bsc_fd *ufd, *tmp;
++int osmo_select_main(int polling)
 +{
-       llist_for_each_entry(ufd, &bsc_fds, list) {
++      struct osmo_fd *ufd, *tmp;
 +      fd_set readset, writeset, exceptset;
 +      int work = 0, rc;
 +      struct timeval no_time = {0, 0};
 +
 +      FD_ZERO(&readset);
 +      FD_ZERO(&writeset);
 +      FD_ZERO(&exceptset);
 +
 +      /* prepare read and write fdsets */
-       bsc_timer_check();
++      llist_for_each_entry(ufd, &osmo_fds, list) {
 +              if (ufd->when & BSC_FD_READ)
 +                      FD_SET(ufd->fd, &readset);
 +
 +              if (ufd->when & BSC_FD_WRITE)
 +                      FD_SET(ufd->fd, &writeset);
 +
 +              if (ufd->when & BSC_FD_EXCEPT)
 +                      FD_SET(ufd->fd, &exceptset);
 +      }
 +
-               bsc_prepare_timers();
-       rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer());
++      osmo_timers_check();
 +
 +      if (!polling)
-       bsc_update_timers();
++              osmo_timers_prepare();
++      rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest());
 +      if (rc < 0)
 +              return 0;
 +
 +      /* fire timers */
-       llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) {
++      osmo_timers_update();
 +
 +      /* call registered callback functions */
 +restart:
 +      unregistered_count = 0;
++      llist_for_each_entry_safe(ufd, tmp, &osmo_fds, list) {
 +              int flags = 0;
 +
 +              if (FD_ISSET(ufd->fd, &readset)) {
 +                      flags |= BSC_FD_READ;
 +                      FD_CLR(ufd->fd, &readset);
 +              }
 +
 +              if (FD_ISSET(ufd->fd, &writeset)) {
 +                      flags |= BSC_FD_WRITE;
 +                      FD_CLR(ufd->fd, &writeset);
 +              }
 +
 +              if (FD_ISSET(ufd->fd, &exceptset)) {
 +                      flags |= BSC_FD_EXCEPT;
 +                      FD_CLR(ufd->fd, &exceptset);
 +              }
 +
 +              if (flags) {
 +                      work = 1;
 +                      ufd->cb(ufd, flags);
 +              }
 +              /* ugly, ugly hack. If more than one filedescriptors were
 +               * unregistered, they might have been consecutive and
 +               * llist_for_each_entry_safe() is no longer safe */
 +              /* this seems to happen with the last element of the list as well */
 +              if (unregistered_count >= 1)
 +                      goto restart;
 +      }
 +      return work;
 +}
 +
 +#endif /* _HAVE_SYS_SELECT_H */
index bb5c38e,0000000..bc339bb
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,87 @@@
-       signal_cbfn *cbfn;
 +/* Generic signalling/notification infrastructure */
 +/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <osmocom/core/signal.h>
 +#include <osmocom/core/talloc.h>
 +#include <osmocom/core/linuxlist.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <errno.h>
 +
 +void *tall_sigh_ctx;
 +static LLIST_HEAD(signal_handler_list);
 +
 +struct signal_handler {
 +      struct llist_head entry;
 +      unsigned int subsys;
- int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
++      osmo_signal_cbfn *cbfn;
 +      void *data;
 +};
 +
 +
- void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
++int osmo_signal_register_handler(unsigned int subsys,
++                               osmo_signal_cbfn *cbfn, void *data)
 +{
 +      struct signal_handler *sig_data;
 +
 +      sig_data = talloc(tall_sigh_ctx, struct signal_handler);
 +      if (!sig_data)
 +              return -ENOMEM;
 +
 +      memset(sig_data, 0, sizeof(*sig_data));
 +
 +      sig_data->subsys = subsys;
 +      sig_data->data = data;
 +      sig_data->cbfn = cbfn;
 +
 +      /* FIXME: check if we already have a handler for this subsys/cbfn/data */
 +
 +      llist_add_tail(&sig_data->entry, &signal_handler_list);
 +
 +      return 0;
 +}
 +
- void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data)
++void osmo_signal_unregister_handler(unsigned int subsys,
++                                  osmo_signal_cbfn *cbfn, void *data)
 +{
 +      struct signal_handler *handler;
 +
 +      llist_for_each_entry(handler, &signal_handler_list, entry) {
 +              if (handler->cbfn == cbfn && handler->data == data 
 +                  && subsys == handler->subsys) {
 +                      llist_del(&handler->entry);
 +                      talloc_free(handler);
 +                      break;
 +              }
 +      }
 +}
 +
 +
++void osmo_signal_dispatch(unsigned int subsys, unsigned int signal,
++                        void *signal_data)
 +{
 +      struct signal_handler *handler;
 +
 +      llist_for_each_entry(handler, &signal_handler_list, entry) {
 +              if (handler->subsys != subsys)
 +                      continue;
 +              (*handler->cbfn)(subsys, signal, handler->data, signal_data);
 +      }
 +}
index 83bb6ed,0000000..e28541b
mode 100644,000000..100644
--- /dev/null
@@@ -1,75 -1,0 +1,76 @@@
- struct counter *counter_alloc(const char *name)
 +/* utility routines for keeping some statistics */
 +
 +/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <string.h>
 +
 +#include <osmocom/core/linuxlist.h>
 +#include <osmocom/core/talloc.h>
 +#include <osmocom/core/statistics.h>
 +
 +static LLIST_HEAD(counters);
 +
 +void *tall_ctr_ctx;
 +
-       struct counter *ctr = talloc_zero(tall_ctr_ctx, struct counter);
++struct osmo_counter *osmo_counter_alloc(const char *name)
 +{
- void counter_free(struct counter *ctr)
++      struct osmo_counter *ctr = talloc_zero(tall_ctr_ctx, struct osmo_counter);
 +
 +      if (!ctr)
 +              return NULL;
 +
 +      ctr->name = name;
 +      llist_add_tail(&ctr->list, &counters);
 +
 +      return ctr;
 +}
 +
- int counters_for_each(int (*handle_counter)(struct counter *, void *), void *data)
++void osmo_counter_free(struct osmo_counter *ctr)
 +{
 +      llist_del(&ctr->list);
 +      talloc_free(ctr);
 +}
 +
-       struct counter *ctr;
++int osmo_counters_for_each(int (*handle_counter)(struct osmo_counter *, void *),
++                         void *data)
 +{
- struct counter *counter_get_by_name(const char *name)
++      struct osmo_counter *ctr;
 +      int rc = 0;
 +
 +      llist_for_each_entry(ctr, &counters, list) {
 +              rc = handle_counter(ctr, data);
 +              if (rc < 0)
 +                      return rc;
 +      }
 +
 +      return rc;
 +}
 +
-       struct counter *ctr;
++struct osmo_counter *osmo_counter_get_by_name(const char *name)
 +{
++      struct osmo_counter *ctr;
 +
 +      llist_for_each_entry(ctr, &counters, list) {
 +              if (!strcmp(ctr->name, name))
 +                      return ctr;
 +      }
 +      return NULL;
 +}
index 9b2dd9e,0000000..ec75212
mode 100644,000000..100644
--- /dev/null
@@@ -1,185 -1,0 +1,186 @@@
- void bsc_add_timer(struct timer_list *timer)
 +/*
 + * (C) 2008,2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <assert.h>
 +#include <string.h>
 +#include <osmocom/core/timer.h>
 +
 +static LLIST_HEAD(timer_list);
 +static struct timeval s_nearest_time;
 +static struct timeval s_select_time;
 +
 +#define MICRO_SECONDS  1000000LL
 +
 +#define TIME_SMALLER(left, right) \
 +        (left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec)
 +
-       struct timer_list *list_timer;
++void osmo_timer_add(struct osmo_timer_list *timer)
 +{
- void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds)
++      struct osmo_timer_list *list_timer;
 +
 +      /* TODO: Optimize and remember the closest item... */
 +      timer->active = 1;
 +
 +      /* this might be called from within update_timers */
 +      llist_for_each_entry(list_timer, &timer_list, entry)
 +              if (timer == list_timer)
 +                      return;
 +
 +      timer->in_list = 1;
 +      llist_add(&timer->entry, &timer_list);
 +}
 +
-       bsc_add_timer(timer);
++void
++osmo_timer_schedule(struct osmo_timer_list *timer, int seconds, int microseconds)
 +{
 +      struct timeval current_time;
 +
 +      gettimeofday(&current_time, NULL);
 +      unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
 +      currentTime += seconds * MICRO_SECONDS + microseconds;
 +      timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
 +      timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
- void bsc_del_timer(struct timer_list *timer)
++      osmo_timer_add(timer);
 +}
 +
- int bsc_timer_pending(struct timer_list *timer)
++void osmo_timer_del(struct osmo_timer_list *timer)
 +{
 +      if (timer->in_list) {
 +              timer->active = 0;
 +              timer->in_list = 0;
 +              llist_del(&timer->entry);
 +      }
 +}
 +
- struct timeval *bsc_nearest_timer()
++int osmo_timer_pending(struct osmo_timer_list *timer)
 +{
 +      return timer->active;
 +}
 +
 +/*
 + * if we have a nearest time return the delta between the current
 + * time and the time of the nearest timer.
 + * If the nearest timer timed out return NULL and then we will
 + * dispatch everything after the select
 + */
- void bsc_prepare_timers()
++struct timeval *osmo_timers_nearest()
 +{
 +      struct timeval current_time;
 +
 +      if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
 +              return NULL;
 +
 +      if (gettimeofday(&current_time, NULL) == -1)
 +              return NULL;
 +
 +      unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
 +      unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
 +
 +      if (nearestTime < currentTime) {
 +              s_select_time.tv_sec = 0;
 +              s_select_time.tv_usec = 0;
 +      } else {
 +              s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
 +              s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
 +      }
 +
 +      return &s_select_time;
 +}
 +
 +/*
 + * Find the nearest time and update s_nearest_time
 + */
-       struct timer_list *timer, *nearest_timer = NULL;
++void osmo_timers_prepare()
 +{
- int bsc_update_timers()
++      struct osmo_timer_list *timer, *nearest_timer = NULL;
 +      llist_for_each_entry(timer, &timer_list, entry) {
 +              if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) {
 +                      nearest_timer = timer;
 +              }
 +      }
 +
 +      if (nearest_timer) {
 +              s_nearest_time = nearest_timer->timeout;
 +      } else {
 +              memset(&s_nearest_time, 0, sizeof(struct timeval));
 +      }
 +}
 +
 +/*
 + * fire all timers... and remove them
 + */
-       struct timer_list *timer, *tmp;
++int osmo_timers_update()
 +{
 +      struct timeval current_time;
-                       bsc_del_timer(timer);
++      struct osmo_timer_list *timer, *tmp;
 +      int work = 0;
 +
 +      gettimeofday(&current_time, NULL);
 +
 +      /*
 +       * The callbacks might mess with our list and in this case
 +       * even llist_for_each_entry_safe is not safe to use. To allow
 +       * del_timer, add_timer, schedule_timer to be called from within
 +       * the callback we jump through some loops.
 +       *
 +       * First we set the handled flag of each active timer to zero,
 +       * then we iterate over the list and execute the callbacks. As the
 +       * list might have been changed (specially the next) from within
 +       * the callback we have to start over again. Once every callback
 +       * is dispatched we will remove the non-active from the list.
 +       *
 +       * TODO: If this is a performance issue we can poison a global
 +       * variable in add_timer and del_timer and only then restart.
 +       */
 +      llist_for_each_entry(timer, &timer_list, entry) {
 +              timer->handled = 0;
 +      }
 +
 +restart:
 +      llist_for_each_entry(timer, &timer_list, entry) {
 +              if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) {
 +                      timer->handled = 1;
 +                      timer->active = 0;
 +                      (*timer->cb)(timer->data);
 +                      work = 1;
 +                      goto restart;
 +              }
 +      }
 +
 +      llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
 +              timer->handled = 0;
 +              if (!timer->active) {
- int bsc_timer_check(void)
++                      osmo_timer_del(timer);
 +              }
 +      }
 +
 +      return work;
 +}
 +
-       struct timer_list *timer;
++int osmo_timers_check(void)
 +{
++      struct osmo_timer_list *timer;
 +      int i = 0;
 +
 +      llist_for_each_entry(timer, &timer_list, entry) {
 +              i++;
 +      }
 +      return i;
 +}
index af1829c,0000000..3ee14ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,158 -1,0 +1,158 @@@
- char bcd2char(uint8_t bcd)
 +
 +#include <string.h>
 +#include <stdint.h>
 +#include <errno.h>
 +#include <stdio.h>
 +
 +#include <osmocom/core/utils.h>
 +
 +static char namebuf[255];
 +const char *get_value_string(const struct value_string *vs, uint32_t val)
 +{
 +      int i;
 +
 +      for (i = 0;; i++) {
 +              if (vs[i].value == 0 && vs[i].str == NULL)
 +                      break;
 +              if (vs[i].value == val)
 +                      return vs[i].str;
 +      }
 +
 +      snprintf(namebuf, sizeof(namebuf), "unknown 0x%x", val);
 +      return namebuf;
 +}
 +
 +int get_string_value(const struct value_string *vs, const char *str)
 +{
 +      int i;
 +
 +      for (i = 0;; i++) {
 +              if (vs[i].value == 0 && vs[i].str == NULL)
 +                      break;
 +              if (!strcasecmp(vs[i].str, str))
 +                      return vs[i].value;
 +      }
 +      return -EINVAL;
 +}
 +
- uint8_t char2bcd(char c)
++char osmo_bcd2char(uint8_t bcd)
 +{
 +      if (bcd < 0xa)
 +              return '0' + bcd;
 +      else
 +              return 'A' + (bcd - 0xa);
 +}
 +
 +/* only works for numbers in ascii */
- int hexparse(const char *str, uint8_t *b, int max_len)
++uint8_t osmo_char2bcd(char c)
 +{
 +      return c - 0x30;
 +}
 +
- static char *_hexdump(const unsigned char *buf, int len, char *delim)
++int osmo_hexparse(const char *str, uint8_t *b, int max_len)
 +
 +{
 +      int i, l, v;
 +
 +      l = strlen(str);
 +      if ((l&1) || ((l>>1) > max_len))
 +              return -1;
 +
 +      memset(b, 0x00, max_len);
 +
 +      for (i=0; i<l; i++) {
 +              char c = str[i];
 +              if (c >= '0' && c <= '9')
 +                      v = c - '0';
 +              else if (c >= 'a' && c <= 'f')
 +                      v = 10 + (c - 'a');
 +              else if (c >= 'A' && c <= 'F')
 +                      v = 10 + (c - 'A');
 +              else
 +                      return -1;
 +              b[i>>1] |= v << (i&1 ? 0 : 4);
 +      }
 +
 +      return i>>1;
 +}
 +
 +static char hexd_buff[4096];
 +
- char *ubit_dump(const uint8_t *bits, unsigned int len)
++static char *_osmo_hexdump(const unsigned char *buf, int len, char *delim)
 +{
 +      int i;
 +      char *cur = hexd_buff;
 +
 +      hexd_buff[0] = 0;
 +      for (i = 0; i < len; i++) {
 +              int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
 +              int rc = snprintf(cur, len_remain, "%02x%s", buf[i], delim);
 +              if (rc <= 0)
 +                      break;
 +              cur += rc;
 +      }
 +      hexd_buff[sizeof(hexd_buff)-1] = 0;
 +      return hexd_buff;
 +}
 +
- char *hexdump(const unsigned char *buf, int len)
++char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)
 +{
 +      int i;
 +
 +      if (len > sizeof(hexd_buff)-1)
 +              len = sizeof(hexd_buff)-1;
 +      memset(hexd_buff, 0, sizeof(hexd_buff));
 +
 +      for (i = 0; i < len; i++) {
 +              char outch;
 +              switch (bits[i]) {
 +              case 0:
 +                      outch = '0';
 +                      break;
 +              case 0xff:
 +                      outch = '?';
 +                      break;
 +              case 1:
 +                      outch = '1';
 +                      break;
 +              default:
 +                      outch = 'E';
 +                      break;
 +              }
 +              hexd_buff[i] = outch;
 +      }
 +      hexd_buff[sizeof(hexd_buff)-1] = 0;
 +      return hexd_buff;
 +}
 +
-       return _hexdump(buf, len, " ");
++char *osmo_hexdump(const unsigned char *buf, int len)
 +{
- char *hexdump_nospc(const unsigned char *buf, int len)
++      return _osmo_hexdump(buf, len, " ");
 +}
 +
-       return _hexdump(buf, len, "");
++char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len)
 +{
++      return _osmo_hexdump(buf, len, "");
 +}
 +
 +#include "../config.h"
 +#ifdef HAVE_CTYPE_H
 +#include <ctype.h>
 +void osmo_str2lower(char *out, const char *in)
 +{
 +      unsigned int i;
 +
 +      for (i = 0; i < strlen(in); i++)
 +              out[i] = tolower(in[i]);
 +      out[strlen(in)] = '\0';
 +}
 +
 +void osmo_str2upper(char *out, const char *in)
 +{
 +      unsigned int i;
 +
 +      for (i = 0; i < strlen(in); i++)
 +              out[i] = toupper(in[i]);
 +      out[strlen(in)] = '\0';
 +}
 +#endif /* HAVE_CTYPE_H */
index 7353ab8,0000000..b7be6f8
mode 100644,000000..100644
--- /dev/null
@@@ -1,14 -1,0 +1,15 @@@
 +# This is _NOT_ the library release version, it's an API version.
 +# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
 +LIBVERSION=0:0:0
 +
 +INCLUDES = $(all_includes) -I$(top_srcdir)/include
 +AM_CFLAGS = -fPIC -Wall
 +
 +if ENABLE_VTY
 +lib_LTLIBRARIES = libosmovty.la
 +
 +libosmovty_la_SOURCES = buffer.c command.c vty.c vector.c utils.c \
 +                      telnet_interface.c logging_vty.c
++libosmovty_la_LDFLAGS = -version-info $(LIBVERSION)
 +libosmovty_la_LIBADD = $(top_builddir)/src/libosmocore.la
 +endif
index 0d45d61,0000000..7845994
mode 100644,000000..100644
--- /dev/null
@@@ -1,206 -1,0 +1,206 @@@
- static int telnet_new_connection(struct bsc_fd *fd, unsigned int what);
 +/* minimalistic telnet/network interface it might turn into a wire interface */
 +/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <sys/socket.h>
 +#include <netinet/in.h>
 +#include <stdlib.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <unistd.h>
 +
 +#include <osmocom/core/msgb.h>
 +#include <osmocom/core/talloc.h>
 +#include <osmocom/core/logging.h>
 +
 +#include <osmocom/vty/telnet_interface.h>
 +#include <osmocom/vty/buffer.h>
 +#include <osmocom/vty/command.h>
 +
 +/* per connection data */
 +LLIST_HEAD(active_connections);
 +
 +static void *tall_telnet_ctx;
 +
 +/* per network data */
- static struct bsc_fd server_socket = {
++static int telnet_new_connection(struct osmo_fd *fd, unsigned int what);
 +
-       bsc_register_fd(&server_socket);
++static struct osmo_fd server_socket = {
 +      .when       = BSC_FD_READ,
 +      .cb         = telnet_new_connection,
 +      .priv_nr    = 0,
 +};
 +
 +int telnet_init(void *tall_ctx, void *priv, int port)
 +{
 +      struct sockaddr_in sock_addr;
 +      int fd, rc, on = 1;
 +
 +      tall_telnet_ctx = talloc_named_const(tall_ctx, 1,
 +                                           "telnet_connection");
 +
 +      fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 +
 +      if (fd < 0) {
 +              LOGP(0, LOGL_ERROR, "Telnet interface socket creation failed\n");
 +              return fd;
 +      }
 +
 +      setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
 +
 +      memset(&sock_addr, 0, sizeof(sock_addr));
 +      sock_addr.sin_family = AF_INET;
 +      sock_addr.sin_port = htons(port);
 +      sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 +
 +      rc = bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
 +      if (rc < 0) {
 +              LOGP(0, LOGL_ERROR, "Telnet interface failed to bind\n");
 +              close(fd);
 +              return rc;
 +      }
 +
 +      rc = listen(fd, 0);
 +      if (rc < 0) {
 +              LOGP(0, LOGL_ERROR, "Telnet interface failed to listen\n");
 +              close(fd);
 +              return rc;
 +      }
 +
 +      server_socket.data = priv;
 +      server_socket.fd = fd;
- int telnet_close_client(struct bsc_fd *fd)
++      osmo_fd_register(&server_socket);
 +
 +      return 0;
 +}
 +
 +extern struct host host;
 +
 +static void print_welcome(int fd)
 +{
 +      int ret;
 +      static char *msg =
 +              "Welcome to the OpenBSC Control interface\r\n";
 +
 +      ret = write(fd, msg, strlen(msg));
 +
 +      if (host.app_info->copyright)
 +              ret = write(fd, host.app_info->copyright, strlen(host.app_info->copyright));
 +}
 +
-       bsc_unregister_fd(fd);
++int telnet_close_client(struct osmo_fd *fd)
 +{
 +      struct telnet_connection *conn = (struct telnet_connection*)fd->data;
 +
 +      close(fd->fd);
- static int client_data(struct bsc_fd *fd, unsigned int what)
++      osmo_fd_unregister(fd);
 +
 +      if (conn->dbg) {
 +              log_del_target(conn->dbg);
 +              talloc_free(conn->dbg);
 +      }
 +
 +      llist_del(&conn->entry);
 +      talloc_free(conn);
 +      return 0;
 +}
 +
- static int telnet_new_connection(struct bsc_fd *fd, unsigned int what)
++static int client_data(struct osmo_fd *fd, unsigned int what)
 +{
 +      struct telnet_connection *conn = fd->data;
 +      int rc = 0;
 +
 +      if (what & BSC_FD_READ) {
 +              conn->fd.when &= ~BSC_FD_READ;
 +              rc = vty_read(conn->vty);
 +      }
 +
 +      /* vty might have been closed from vithin vty_read() */
 +      if (!conn->vty)
 +              return rc;
 +
 +      if (what & BSC_FD_WRITE) {
 +              rc = buffer_flush_all(conn->vty->obuf, fd->fd);
 +              if (rc == BUFFER_EMPTY)
 +                      conn->fd.when &= ~BSC_FD_WRITE;
 +      }
 +
 +      return rc;
 +}
 +
-       bsc_register_fd(&connection->fd);
++static int telnet_new_connection(struct osmo_fd *fd, unsigned int what)
 +{
 +      struct telnet_connection *connection;
 +      struct sockaddr_in sockaddr;
 +      socklen_t len = sizeof(sockaddr);
 +      int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
 +
 +      if (new_connection < 0) {
 +              LOGP(0, LOGL_ERROR, "telnet accept failed\n");
 +              return new_connection;
 +      }
 +
 +      connection = talloc_zero(tall_telnet_ctx, struct telnet_connection);
 +      connection->priv = fd->data;
 +      connection->fd.data = connection;
 +      connection->fd.fd = new_connection;
 +      connection->fd.when = BSC_FD_READ;
 +      connection->fd.cb = client_data;
-       struct bsc_fd *bfd = &connection->fd;
++      osmo_fd_register(&connection->fd);
 +      llist_add_tail(&connection->entry, &active_connections);
 +
 +      print_welcome(new_connection);
 +
 +      connection->vty = vty_create(new_connection, connection);
 +      if (!connection->vty) {
 +              LOGP(0, LOGL_ERROR, "couldn't create VTY\n");
 +              close(new_connection);
 +              talloc_free(connection);
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +/* callback from VTY code */
 +void vty_event(enum event event, int sock, struct vty *vty)
 +{
 +      struct telnet_connection *connection = vty->priv;
++      struct osmo_fd *bfd = &connection->fd;
 +
 +      if (vty->type != VTY_TERM)
 +              return;
 +
 +      switch (event) {
 +      case VTY_READ:
 +              bfd->when |= BSC_FD_READ;
 +              break;
 +      case VTY_WRITE:
 +              bfd->when |= BSC_FD_WRITE;
 +              break;
 +      case VTY_CLOSED:
 +              /* vty layer is about to free() vty */
 +              connection->vty = NULL;
 +              telnet_close_client(bfd);
 +              break;
 +      default:
 +              break;
 +      }
 +}
 +
index 0642aad,0000000..a592104
mode 100644,000000..100644
--- /dev/null
@@@ -1,90 -1,0 +1,90 @@@
- int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what)
 +/* 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.
 + *
 + */
 +
 +#include <osmocom/core/write_queue.h>
 +
-       struct write_queue *queue;
++int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what)
 +{
-       queue = container_of(fd, struct write_queue, bfd);
++      struct osmo_wqueue *queue;
 +
- void write_queue_init(struct write_queue *queue, int max_length)
++      queue = container_of(fd, struct osmo_wqueue, bfd);
 +
 +      if (what & BSC_FD_READ)
 +              queue->read_cb(fd);
 +
 +      if (what & BSC_FD_EXCEPT)
 +              queue->except_cb(fd);
 +
 +      if (what & BSC_FD_WRITE) {
 +              struct msgb *msg;
 +
 +              fd->when &= ~BSC_FD_WRITE;
 +
 +              /* the queue might have been emptied */
 +              if (!llist_empty(&queue->msg_queue)) {
 +                      --queue->current_length;
 +
 +                      msg = msgb_dequeue(&queue->msg_queue);
 +                      queue->write_cb(fd, msg);
 +                      msgb_free(msg);
 +
 +                      if (!llist_empty(&queue->msg_queue))
 +                              fd->when |= BSC_FD_WRITE;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
-       queue->bfd.cb = write_queue_bfd_cb;
++void osmo_wqueue_init(struct osmo_wqueue *queue, int max_length)
 +{
 +      queue->max_length = max_length;
 +      queue->current_length = 0;
 +      queue->read_cb = NULL;
 +      queue->write_cb = NULL;
- int write_queue_enqueue(struct write_queue *queue, struct msgb *data)
++      queue->bfd.cb = osmo_wqueue_bfd_cb;
 +      INIT_LLIST_HEAD(&queue->msg_queue);
 +}
 +
- void write_queue_clear(struct write_queue *queue)
++int osmo_wqueue_enqueue(struct osmo_wqueue *queue, struct msgb *data)
 +{
 +//    if (queue->current_length + 1 >= queue->max_length)
 +//            LOGP(DMSC, LOGL_ERROR, "The queue is full. Dropping not yet implemented.\n");
 +
 +      ++queue->current_length;
 +      msgb_enqueue(&queue->msg_queue, data);
 +      queue->bfd.when |= BSC_FD_WRITE;
 +
 +      return 0;
 +}
 +
++void osmo_wqueue_clear(struct osmo_wqueue *queue)
 +{
 +      while (!llist_empty(&queue->msg_queue)) {
 +              struct msgb *msg = msgb_dequeue(&queue->msg_queue);
 +              msgb_free(msg);
 +      }
 +
 +      queue->current_length = 0;
 +      queue->bfd.when &= ~BSC_FD_WRITE;
 +}
index 4637cea,0000000..ed7aa97
mode 100644,000000..100644
--- /dev/null
@@@ -1,50 -1,0 +1,50 @@@
- static void dump_entries(struct msg_entries *entries)
 +/*
 + * (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.
 + *
 + */
 +
 +#include <osmocom/core/msgfile.h>
 +
 +#include <stdio.h>
 +
-       struct msg_entry *entry;
++static void dump_entries(struct osmo_config_list *entries)
 +{
-       struct msg_entries *entries;
++      struct osmo_config_entry *entry;
 +
 +      if (!entries) {
 +              fprintf(stderr, "Failed to parse the file\n");
 +              return;
 +      }
 +
 +      llist_for_each_entry(entry, &entries->entry, list) {
 +              printf("Entry '%s:%s:%s:%s'\n",
 +                      entry->mcc, entry->mnc, entry->option, entry->text);
 +      }
 +}
 +
 +int main(int argc, char **argv)
 +{
-       entries = msg_entry_parse(NULL, "msgconfig.cfg");
++      struct osmo_config_list *entries;
 +
 +      /* todo use msgfile_test.c.in and replace the path */
++      entries = osmo_config_list_parse(NULL, "msgconfig.cfg");
 +      dump_entries(entries);
 +
 +      return 0;
 +}
index 30b08ad,0000000..240bc48
mode 100644,000000..100644
--- /dev/null
@@@ -1,77 -1,0 +1,77 @@@
- static struct timer_list timer_one = {
 +/*
 + * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <stdio.h>
 +
 +#include <osmocom/core/timer.h>
 +#include <osmocom/core/select.h>
 +
 +#include "../../config.h"
 +
 +static void timer_fired(void *data);
 +
- static struct timer_list timer_two = {
++static struct osmo_timer_list timer_one = {
 +    .cb = timer_fired,
 +    .data = (void*)1,
 +};
 +
- static struct timer_list timer_three = {
++static struct osmo_timer_list timer_two = {
 +    .cb = timer_fired,
 +    .data = (void*)2,
 +};
 +
-         bsc_schedule_timer(&timer_one, 3, 0);
-         bsc_del_timer(&timer_two);
++static struct osmo_timer_list timer_three = {
 +    .cb = timer_fired,
 +    .data = (void*)3,
 +};
 +
 +static void timer_fired(void *_data)
 +{
 +    unsigned long data = (unsigned long) _data;
 +    printf("Fired timer: %lu\n", data);
 +
 +    if (data == 1) {
-     bsc_schedule_timer(&timer_one, 3, 0);
-     bsc_schedule_timer(&timer_two, 5, 0);
-     bsc_schedule_timer(&timer_three, 4, 0);
++        osmo_timer_schedule(&timer_one, 3, 0);
++        osmo_timer_del(&timer_two);
 +    } else if (data == 2) {
 +        printf("Should not be fired... bug in del_timer\n");
 +    } else if (data == 3) {
 +        printf("Timer fired not registering again\n");
 +    } else  {
 +        printf("wtf... wrong data\n");
 +    }
 +}
 +
 +int main(int argc, char** argv)
 +{
 +    printf("Starting... timer\n");
 +
-         bsc_select_main(0);
++    osmo_timer_schedule(&timer_one, 3, 0);
++    osmo_timer_schedule(&timer_two, 5, 0);
++    osmo_timer_schedule(&timer_three, 4, 0);
 +
 +#ifdef HAVE_SYS_SELECT_H
 +    while (1) {
++        osmo_select_main(0);
 +    }
 +#else
 +    printf("Select not supported on this platform!\n");
 +#endif
 +}