Merge commit '622b718195d607d7cfc8b9ec96f943ea0ce2d1dd'
authorHarald Welte <laforge@gnumonks.org>
Sun, 7 Mar 2010 16:51:35 +0000 (17:51 +0100)
committerHarald Welte <laforge@gnumonks.org>
Sun, 7 Mar 2010 16:51:35 +0000 (17:51 +0100)
1  2 
src/shared/libosmocore/include/osmocore/Makefile.am
src/shared/libosmocore/include/osmocore/bitvec.h
src/shared/libosmocore/include/osmocore/gsm_utils.h
src/shared/libosmocore/include/osmocore/gsmtap.h
src/shared/libosmocore/include/osmocore/protocol/gsm_12_21.h
src/shared/libosmocore/include/osmocore/rxlev_stat.h
src/shared/libosmocore/src/Makefile.am
src/shared/libosmocore/src/bitvec.c
src/shared/libosmocore/src/gsm_utils.c
src/shared/libosmocore/src/rxlev_stat.c

index b45d023,0000000..9c4fc75
mode 100644,000000..100644
--- /dev/null
@@@ -1,7 -1,0 +1,7 @@@
-                  gsmtap.h write_queue.h rsl.h gsm48.h
 +osmocore_HEADERS = signal.h linuxlist.h timer.h talloc.h msgb.h select.h \
 +                 tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \
++                 gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h
 +
 +osmocoredir = $(includedir)/osmocore
 +
 +SUBDIRS = protocol
index 11cb01e,0000000..7a26bce
mode 100644,000000..100644
--- /dev/null
@@@ -1,65 -1,0 +1,65 @@@
- enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr);
 +#ifndef _BITVEC_H
 +#define _BITVEC_H
 +
 +/* bit vector utility routines */
 +
 +/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +
 +/* In GSM mac blocks, every bit can be 0 or 1, or L or H.  L/H are
 + * defined relative to the 0x2b padding pattern */
 +enum bit_value {
 +      ZERO    = 0,
 +      ONE     = 1,
 +      L       = 2,
 +      H       = 3,
 +};
 +
 +struct bitvec {
 +      unsigned int cur_bit;   /* curser to the next unused bit */
 +      unsigned int data_len;  /* length of data array in bytes */
 +      uint8_t *data;          /* pointer to data array */
 +};
 +
 +/* check if the bit is 0 or 1 for a given position inside a bitvec */
- unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n);
++enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr);
 +
 +/* get the Nth set bit inside the bit vector */
++unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n);
 +
 +/* Set a bit at given position */
 +int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
 +                      enum bit_value bit);
 +
 +/* Set the next bit in the vector */
 +int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
 +
 +/* Set multiple bits at the current position */
 +int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count);
 +
 +/* Add an unsigned integer (of length count bits) to current position */
 +int bitvec_set_uint(struct bitvec *bv, unsigned int in, int count);
 +
 +
 +/* Pad the bit vector up to a certain bit position */
 +int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit);
 +
 +#endif /* _BITVEC_H */
index b611050,0000000..2536045
mode 100644,000000..100644
--- /dev/null
@@@ -1,62 -1,0 +1,84 @@@
 +/* GSM utility functions, e.g. coding and decoding */
 +/*
 + * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
 + * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
 + * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#ifndef GSM_UTILS_H
 +#define GSM_UTILS_H
 +
 +#include <stdint.h>
 +
++struct gsm_time {
++      uint32_t        fn;     /* FN count */
++      uint16_t        t1;     /* FN div (26*51) */
++      uint8_t         t2;     /* FN modulo 26 */
++      uint8_t         t3;     /* FN modulo 51 */
++      uint8_t         tc;
++};
++
 +enum gsm_band {
 +      GSM_BAND_850    = 1,
 +      GSM_BAND_900    = 2,
 +      GSM_BAND_1800   = 4,
 +      GSM_BAND_1900   = 8,
 +      GSM_BAND_450    = 0x10,
 +      GSM_BAND_480    = 0x20,
 +      GSM_BAND_750    = 0x40,
 +      GSM_BAND_810    = 0x80,
 +};
 +
 +char *gsm_band_name(enum gsm_band band);
 +enum gsm_band gsm_band_parse(const char *mhz);
 +
 +int gsm_7bit_decode(char *decoded, const uint8_t *user_data, uint8_t length);
 +int gsm_7bit_encode(uint8_t *result, const char *data);
 +
 +int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm);
 +int ms_pwr_dbm(enum gsm_band band, uint8_t lvl);
 +
 +/* According to TS 08.05 Chapter 8.1.4 */
 +int rxlev2dbm(uint8_t rxlev);
 +uint8_t dbm2rxlev(int dbm);
 +
 +/* According to GSM 04.08 Chapter 10.5.2.29 */
 +static inline int rach_max_trans_val2raw(int val) { return (val >> 1) & 3; }
 +static inline int rach_max_trans_raw2val(int raw) {
 +      const int tbl[4] = { 1, 2, 4, 7 };
 +      return tbl[raw & 3];
 +}
 +
++#define       ARFCN_PCS       0x8000
++#define       ARFCN_UPLINK    0x4000
++
++enum gsm_band gsm_arfcn2band(uint16_t arfcn);
++
++/* Convert an ARFCN to the frequency in MHz * 10 */
++uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink);
++
++/* Convert from frame number to GSM time */
++void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn);
++
++/* Convert from GSM time to frame number */
++uint32_t gsm_gsmtime2fn(struct gsm_time *time);
++
 +void generate_backtrace();
 +#endif
index d6d40ba,0000000..dcd64bd
mode 100644,000000..100644
--- /dev/null
@@@ -1,68 -1,0 +1,72 @@@
 +#ifndef _GSMTAP_H
 +#define _GSMTAP_H
 +
 +/* gsmtap header, pseudo-header in front of the actua GSM payload */
 +
 +/* GSMTAP is a generic header format for GSM protocol captures,
 + * it uses the IANA-assigned UDP port number 4729 and carries
 + * payload in various formats of GSM interfaces such as Um MAC
 + * blocks or Um bursts.
 + *
 + * Example programs generating GSMTAP data are airprobe
 + * (http://airprobe.org/) or OsmocomBB (http://bb.osmocom.org/)
 + */
 +
 +#include <stdint.h>
 +
 +#define GSMTAP_VERSION                0x02
 +
 +#define GSMTAP_TYPE_UM                0x01
 +#define GSMTAP_TYPE_ABIS      0x02
 +#define GSMTAP_TYPE_UM_BURST  0x03    /* raw burst bits */
 +
 +#define GSMTAP_BURST_UNKNOWN          0x00
 +#define GSMTAP_BURST_FCCH             0x01
 +#define GSMTAP_BURST_PARTIAL_SCH      0x02
 +#define GSMTAP_BURST_SCH              0x03
 +#define GSMTAP_BURST_CTS_SCH          0x04
 +#define GSMTAP_BURST_COMPACT_SCH      0x05
 +#define GSMTAP_BURST_NORMAL           0x06
 +#define GSMTAP_BURST_DUMMY            0x07
 +#define GSMTAP_BURST_ACCESS           0x08
 +#define GSMTAP_BURST_NONE             0x09
 +
 +#define GSMTAP_CHANNEL_UNKNOWN        0x00
 +#define GSMTAP_CHANNEL_BCCH   0x01
 +#define GSMTAP_CHANNEL_CCCH   0x02
 +#define GSMTAP_CHANNEL_RACH   0x03
 +#define GSMTAP_CHANNEL_AGCH   0x04
 +#define GSMTAP_CHANNEL_PCH    0x05
 +#define GSMTAP_CHANNEL_SDCCH  0x06
 +#define GSMTAP_CHANNEL_SDCCH4 0x07
 +#define GSMTAP_CHANNEL_SDCCH8 0x08
 +#define GSMTAP_CHANNEL_TCH_F  0x09
 +#define GSMTAP_CHANNEL_TCH_H  0x0a
 +#define GSMTAP_CHANNEL_ACCH   0x80
 +
++#define GSMTAP_ARFCN_F_PCS    0x8000
++#define GSMTAP_ARFCN_F_UPLINK 0x4000
++#define GSMTAP_ARFCN_MASK     0x3fff
++
 +#define GSMTAP_UDP_PORT                       4729
 +
 +struct gsmtap_hdr {
 +      uint8_t version;        /* version, set to 0x01 currently */
 +      uint8_t hdr_len;        /* length in number of 32bit words */
 +      uint8_t type;           /* see GSMTAP_TYPE_* */
 +      uint8_t timeslot;       /* timeslot (0..7 on Um) */
 +
 +      uint16_t arfcn;         /* ARFCN (frequency) */
 +      int8_t signal_dbm;      /* signal level in dBm */
 +      int8_t snr_db;          /* signal/noise ratio in dB */
 +
 +      uint32_t frame_number;  /* GSM Frame Number (FN) */
 +
 +      uint8_t sub_type;       /* Type of burst/channel, see above */
 +      uint8_t antenna_nr;     /* Antenna Number */
 +      uint8_t sub_slot;       /* sub-slot within timeslot */
 +      uint8_t res;            /* reserved for future use (RFU) */
 +
 +} __attribute__((packed));
 +
 +#endif /* _GSMTAP_H */
index ac6db4b,0000000..9cae45d
mode 100644,000000..100644
--- /dev/null
@@@ -1,691 -1,0 +1,713 @@@
 +#ifndef PROTO_GSM_12_21_H
 +#define PROTO_GSM_12_21_H
 +
 +/* GSM Network Management messages on the A-bis interface 
 + * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
 +
 +/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +#include <stdint.h>
 +#include <osmocore/tlv.h>
 +
 +/* generic header in front of every OML message according to TS 08.59 */
 +struct abis_om_hdr {
 +      uint8_t mdisc;
 +      uint8_t placement;
 +      uint8_t sequence;
 +      uint8_t length;
 +      uint8_t data[0];
 +} __attribute__ ((packed));
 +
 +#define ABIS_OM_MDISC_FOM             0x80
 +#define ABIS_OM_MDISC_MMI             0x40
 +#define ABIS_OM_MDISC_TRAU            0x20
 +#define ABIS_OM_MDISC_MANUF           0x10
 +#define ABIS_OM_PLACEMENT_ONLY                0x80
 +#define ABIS_OM_PLACEMENT_FIRST       0x40
 +#define ABIS_OM_PLACEMENT_MIDDLE      0x20
 +#define ABIS_OM_PLACEMENT_LAST                0x10
 +
 +struct abis_om_obj_inst {
 +      uint8_t bts_nr;
 +      uint8_t trx_nr;
 +      uint8_t ts_nr;
 +} __attribute__ ((packed));
 +
 +struct abis_om_fom_hdr {
 +      uint8_t msg_type;
 +      uint8_t obj_class;
 +      struct abis_om_obj_inst obj_inst;
 +      uint8_t data[0];
 +} __attribute__ ((packed));
 +
 +#define ABIS_OM_FOM_HDR_SIZE  (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_fom_hdr))
 +
 +/* Section 9.1: Message Types */
 +enum abis_nm_msgtype {
 +      /* SW Download Management Messages */
 +      NM_MT_LOAD_INIT                 = 0x01,
 +      NM_MT_LOAD_INIT_ACK,
 +      NM_MT_LOAD_INIT_NACK,
 +      NM_MT_LOAD_SEG,
 +      NM_MT_LOAD_SEG_ACK,
 +      NM_MT_LOAD_ABORT,
 +      NM_MT_LOAD_END,
 +      NM_MT_LOAD_END_ACK,
 +      NM_MT_LOAD_END_NACK,
 +      NM_MT_SW_ACT_REQ,               /* BTS->BSC */
 +      NM_MT_SW_ACT_REQ_ACK,
 +      NM_MT_SW_ACT_REQ_NACK,
 +      NM_MT_ACTIVATE_SW,              /* BSC->BTS */
 +      NM_MT_ACTIVATE_SW_ACK,
 +      NM_MT_ACTIVATE_SW_NACK,
 +      NM_MT_SW_ACTIVATED_REP,         /* 0x10 */
 +      /* A-bis Interface Management Messages */
 +      NM_MT_ESTABLISH_TEI             = 0x21,
 +      NM_MT_ESTABLISH_TEI_ACK,
 +      NM_MT_ESTABLISH_TEI_NACK,
 +      NM_MT_CONN_TERR_SIGN,
 +      NM_MT_CONN_TERR_SIGN_ACK,
 +      NM_MT_CONN_TERR_SIGN_NACK,
 +      NM_MT_DISC_TERR_SIGN,
 +      NM_MT_DISC_TERR_SIGN_ACK,
 +      NM_MT_DISC_TERR_SIGN_NACK,
 +      NM_MT_CONN_TERR_TRAF,
 +      NM_MT_CONN_TERR_TRAF_ACK,
 +      NM_MT_CONN_TERR_TRAF_NACK,
 +      NM_MT_DISC_TERR_TRAF,
 +      NM_MT_DISC_TERR_TRAF_ACK,
 +      NM_MT_DISC_TERR_TRAF_NACK,
 +      /* Transmission Management Messages */
 +      NM_MT_CONN_MDROP_LINK           = 0x31,
 +      NM_MT_CONN_MDROP_LINK_ACK,
 +      NM_MT_CONN_MDROP_LINK_NACK,
 +      NM_MT_DISC_MDROP_LINK,
 +      NM_MT_DISC_MDROP_LINK_ACK,
 +      NM_MT_DISC_MDROP_LINK_NACK,
 +      /* Air Interface Management Messages */
 +      NM_MT_SET_BTS_ATTR              = 0x41,
 +      NM_MT_SET_BTS_ATTR_ACK,
 +      NM_MT_SET_BTS_ATTR_NACK,
 +      NM_MT_SET_RADIO_ATTR,
 +      NM_MT_SET_RADIO_ATTR_ACK,
 +      NM_MT_SET_RADIO_ATTR_NACK,
 +      NM_MT_SET_CHAN_ATTR,
 +      NM_MT_SET_CHAN_ATTR_ACK,
 +      NM_MT_SET_CHAN_ATTR_NACK,
 +      /* Test Management Messages */
 +      NM_MT_PERF_TEST                 = 0x51,
 +      NM_MT_PERF_TEST_ACK,
 +      NM_MT_PERF_TEST_NACK,
 +      NM_MT_TEST_REP,
 +      NM_MT_SEND_TEST_REP,
 +      NM_MT_SEND_TEST_REP_ACK,
 +      NM_MT_SEND_TEST_REP_NACK,
 +      NM_MT_STOP_TEST,
 +      NM_MT_STOP_TEST_ACK,
 +      NM_MT_STOP_TEST_NACK,
 +      /* State Management and Event Report Messages */
 +      NM_MT_STATECHG_EVENT_REP        = 0x61,
 +      NM_MT_FAILURE_EVENT_REP,
 +      NM_MT_STOP_EVENT_REP,
 +      NM_MT_STOP_EVENT_REP_ACK,
 +      NM_MT_STOP_EVENT_REP_NACK,
 +      NM_MT_REST_EVENT_REP,
 +      NM_MT_REST_EVENT_REP_ACK,
 +      NM_MT_REST_EVENT_REP_NACK,
 +      NM_MT_CHG_ADM_STATE,
 +      NM_MT_CHG_ADM_STATE_ACK,
 +      NM_MT_CHG_ADM_STATE_NACK,
 +      NM_MT_CHG_ADM_STATE_REQ,
 +      NM_MT_CHG_ADM_STATE_REQ_ACK,
 +      NM_MT_CHG_ADM_STATE_REQ_NACK,
 +      NM_MT_REP_OUTST_ALARMS          = 0x93,
 +      NM_MT_REP_OUTST_ALARMS_ACK,
 +      NM_MT_REP_OUTST_ALARMS_NACK,
 +      /* Equipment Management Messages */
 +      NM_MT_CHANGEOVER                = 0x71,
 +      NM_MT_CHANGEOVER_ACK,
 +      NM_MT_CHANGEOVER_NACK,
 +      NM_MT_OPSTART,
 +      NM_MT_OPSTART_ACK,
 +      NM_MT_OPSTART_NACK,
 +      NM_MT_REINIT,
 +      NM_MT_REINIT_ACK,
 +      NM_MT_REINIT_NACK,
 +      NM_MT_SET_SITE_OUT,             /* BS11: get alarm ?!? */
 +      NM_MT_SET_SITE_OUT_ACK,
 +      NM_MT_SET_SITE_OUT_NACK,
 +      NM_MT_CHG_HW_CONF               = 0x90,
 +      NM_MT_CHG_HW_CONF_ACK,
 +      NM_MT_CHG_HW_CONF_NACK,
 +      /* Measurement Management Messages */
 +      NM_MT_MEAS_RES_REQ              = 0x8a,
 +      NM_MT_MEAS_RES_RESP,
 +      NM_MT_STOP_MEAS,
 +      NM_MT_START_MEAS,
 +      /* Other Messages */
 +      NM_MT_GET_ATTR                  = 0x81,
 +      NM_MT_GET_ATTR_RESP,
 +      NM_MT_GET_ATTR_NACK,
 +      NM_MT_SET_ALARM_THRES,
 +      NM_MT_SET_ALARM_THRES_ACK,
 +      NM_MT_SET_ALARM_THRES_NACK,
 +};
 +
 +enum abis_nm_msgtype_bs11 {
 +      NM_MT_BS11_RESET_RESOURCE       = 0x74,
 +
 +      NM_MT_BS11_BEGIN_DB_TX          = 0xa3,
 +      NM_MT_BS11_BEGIN_DB_TX_ACK,
 +      NM_MT_BS11_BEGIN_DB_TX_NACK,
 +      NM_MT_BS11_END_DB_TX            = 0xa6,
 +      NM_MT_BS11_END_DB_TX_ACK,
 +      NM_MT_BS11_END_DB_TX_NACK,
 +      NM_MT_BS11_CREATE_OBJ           = 0xa9,
 +      NM_MT_BS11_CREATE_OBJ_ACK,
 +      NM_MT_BS11_CREATE_OBJ_NACK,
 +      NM_MT_BS11_DELETE_OBJ           = 0xac,
 +      NM_MT_BS11_DELETE_OBJ_ACK,
 +      NM_MT_BS11_DELETE_OBJ_NACK,
 +
 +      NM_MT_BS11_SET_ATTR             = 0xd0,
 +      NM_MT_BS11_SET_ATTR_ACK,
 +      NM_MT_BS11_SET_ATTR_NACK,
 +      NM_MT_BS11_LMT_SESSION          = 0xdc,
 +
 +      NM_MT_BS11_GET_STATE            = 0xe3,
 +      NM_MT_BS11_GET_STATE_ACK,
 +      NM_MT_BS11_LMT_LOGON            = 0xe5,
 +      NM_MT_BS11_LMT_LOGON_ACK,
 +      NM_MT_BS11_RESTART              = 0xe7,
 +      NM_MT_BS11_RESTART_ACK,
 +      NM_MT_BS11_DISCONNECT           = 0xe9,
 +      NM_MT_BS11_DISCONNECT_ACK,
 +      NM_MT_BS11_LMT_LOGOFF           = 0xec,
 +      NM_MT_BS11_LMT_LOGOFF_ACK,
 +      NM_MT_BS11_RECONNECT            = 0xf1,
 +      NM_MT_BS11_RECONNECT_ACK,
 +};
 +
 +enum abis_nm_msgtype_ipacc {
 +      NM_MT_IPACC_RESTART             = 0x87,
 +      NM_MT_IPACC_RESTART_ACK,
 +      NM_MT_IPACC_RESTART_NACK,
 +      NM_MT_IPACC_RSL_CONNECT         = 0xe0,
 +      NM_MT_IPACC_RSL_CONNECT_ACK,
 +      NM_MT_IPACC_RSL_CONNECT_NACK,
 +      NM_MT_IPACC_RSL_DISCONNECT      = 0xe3,
 +      NM_MT_IPACC_RSL_DISCONNECT_ACK,
 +      NM_MT_IPACC_RSL_DISCONNECT_NACK,
 +      NM_MT_IPACC_CONN_TRAF           = 0xe6,
 +      NM_MT_IPACC_CONN_TRAF_ACK,
 +      NM_MT_IPACC_CONN_TRAF_NACK,
 +      NM_MT_IPACC_DEF_BOOT_SW         = 0xec,
 +      NM_MT_IPACC_DEF_BOOT_SW_ACK,
 +      MN_MT_IPACC_DEF_BOOT_SW_NACK,
 +      NM_MT_IPACC_SET_NVATTR          = 0xef,
 +      NM_MT_IPACC_SET_NVATTR_ACK,
 +      NM_MT_IPACC_SET_NVATTR_NACK,
 +      NM_MT_IPACC_GET_NVATTR          = 0xf2,
 +      NM_MT_IPACC_GET_NVATTR_ACK,
 +      NM_MT_IPACC_GET_NVATTR_NACK,
 +      NM_MT_IPACC_SET_ATTR            = 0xf5,
 +      NM_MT_IPACC_SET_ATTR_ACK,
 +      NM_MT_IPACC_SET_ATTR_NACK,
 +};
 +
 +enum abis_nm_bs11_cell_alloc {
 +      NM_BS11_CANR_GSM        = 0x00,
 +      NM_BS11_CANR_DCS1800    = 0x01,
 +};
 +
 +/* Section 9.2: Object Class */
 +enum abis_nm_obj_class {
 +      NM_OC_SITE_MANAGER              = 0x00,
 +      NM_OC_BTS,
 +      NM_OC_RADIO_CARRIER,
 +      NM_OC_CHANNEL,
 +      NM_OC_BASEB_TRANSC,
 +      /* RFU: 05-FE */
 +
 +      NM_OC_IPAC_E1_TRUNK             = 0x0e,
 +      NM_OC_IPAC_E1_PORT              = 0x0f,
 +      NM_OC_IPAC_E1_CHAN              = 0x10,
 +      NM_OC_IPAC_CLK_MODULE           = 0x22,
 +
 +      NM_OC_BS11_ADJC                 = 0xa0,
 +      NM_OC_BS11_HANDOVER             = 0xa1,
 +      NM_OC_BS11_PWR_CTRL             = 0xa2,
 +      NM_OC_BS11_BTSE                 = 0xa3,         /* LMT? */
 +      NM_OC_BS11_RACK                 = 0xa4,
 +      NM_OC_BS11                      = 0xa5,         /* 01: ALCO */
 +      NM_OC_BS11_TEST                 = 0xa6,
 +      NM_OC_BS11_ENVABTSE             = 0xa8,
 +      NM_OC_BS11_BPORT                = 0xa9,
 +
 +      NM_OC_GPRS_NSE                  = 0xf0,
 +      NM_OC_GPRS_CELL                 = 0xf1,
 +      NM_OC_GPRS_NSVC                 = 0xf2,
 +
 +      NM_OC_NULL                      = 0xff,
 +};
 +
 +/* Section 9.4: Attributes */
 +enum abis_nm_attr {
 +      NM_ATT_ABIS_CHANNEL     = 0x01,
 +      NM_ATT_ADD_INFO,
 +      NM_ATT_ADD_TEXT,
 +      NM_ATT_ADM_STATE,
 +      NM_ATT_ARFCN_LIST,
 +      NM_ATT_AUTON_REPORT,
 +      NM_ATT_AVAIL_STATUS,
 +      NM_ATT_BCCH_ARFCN,
 +      NM_ATT_BSIC,
 +      NM_ATT_BTS_AIR_TIMER,
 +      NM_ATT_CCCH_L_I_P,
 +      NM_ATT_CCCH_L_T,
 +      NM_ATT_CHAN_COMB,
 +      NM_ATT_CONN_FAIL_CRIT,
 +      NM_ATT_DEST,
 +      /* res */
 +      NM_ATT_EVENT_TYPE       = 0x11, /* BS11: file data ?!? */
 +      NM_ATT_FILE_ID,
 +      NM_ATT_FILE_VERSION,
 +      NM_ATT_GSM_TIME,
 +      NM_ATT_HSN,
 +      NM_ATT_HW_CONFIG,
 +      NM_ATT_HW_DESC,
 +      NM_ATT_INTAVE_PARAM,
 +      NM_ATT_INTERF_BOUND,
 +      NM_ATT_LIST_REQ_ATTR,
 +      NM_ATT_MAIO,
 +      NM_ATT_MANUF_STATE,
 +      NM_ATT_MANUF_THRESH,
 +      NM_ATT_MANUF_ID,
 +      NM_ATT_MAX_TA,
 +      NM_ATT_MDROP_LINK,      /* 0x20 */
 +      NM_ATT_MDROP_NEXT,
 +      NM_ATT_NACK_CAUSES,
 +      NM_ATT_NY1,
 +      NM_ATT_OPER_STATE,
 +      NM_ATT_OVERL_PERIOD,
 +      NM_ATT_PHYS_CONF,
 +      NM_ATT_POWER_CLASS,
 +      NM_ATT_POWER_THRESH,
 +      NM_ATT_PROB_CAUSE,
 +      NM_ATT_RACH_B_THRESH,
 +      NM_ATT_LDAVG_SLOTS,
 +      NM_ATT_RAD_SUBC,
 +      NM_ATT_RF_MAXPOWR_R,
 +      NM_ATT_SITE_INPUTS,
 +      NM_ATT_SITE_OUTPUTS,
 +      NM_ATT_SOURCE,          /* 0x30 */
 +      NM_ATT_SPEC_PROB,
 +      NM_ATT_START_TIME,
 +      NM_ATT_T200,
 +      NM_ATT_TEI,
 +      NM_ATT_TEST_DUR,
 +      NM_ATT_TEST_NO,
 +      NM_ATT_TEST_REPORT,
 +      NM_ATT_VSWR_THRESH,
 +      NM_ATT_WINDOW_SIZE,
 +      /* Res  */
 +      NM_ATT_BS11_RSSI_OFFS   = 0x3d,
 +      NM_ATT_BS11_TXPWR       = 0x3e,
 +      NM_ATT_BS11_DIVERSITY   = 0x3f,
 +      /* Res  */
 +      NM_ATT_TSC              = 0x40,
 +      NM_ATT_SW_CONFIG,
 +      NM_ATT_SW_DESCR,
 +      NM_ATT_SEVERITY,
 +      NM_ATT_GET_ARI,
 +      NM_ATT_HW_CONF_CHG,
 +      NM_ATT_OUTST_ALARM,
 +      NM_ATT_FILE_DATA,
 +      NM_ATT_MEAS_RES,
 +      NM_ATT_MEAS_TYPE,
 +
 +      NM_ATT_BS11_ESN_FW_CODE_NO      = 0x4c,
 +      NM_ATT_BS11_ESN_HW_CODE_NO      = 0x4f,
 +
 +      NM_ATT_BS11_ESN_PCB_SERIAL      = 0x55,
 +      NM_ATT_BS11_EXCESSIVE_DISTANCE  = 0x58,
 +
 +      NM_ATT_BS11_ALL_TEST_CATG       = 0x60,
 +      NM_ATT_BS11_BTSLS_HOPPING,
 +      NM_ATT_BS11_CELL_ALLOC_NR,
 +      NM_ATT_BS11_CELL_GLOBAL_ID,
 +      NM_ATT_BS11_ENA_INTERF_CLASS    = 0x66,
 +      NM_ATT_BS11_ENA_INT_INTEC_HANDO = 0x67,
 +      NM_ATT_BS11_ENA_INT_INTRC_HANDO = 0x68,
 +      NM_ATT_BS11_ENA_MS_PWR_CTRL     = 0x69,
 +      NM_ATT_BS11_ENA_PWR_BDGT_HO     = 0x6a,
 +      NM_ATT_BS11_ENA_PWR_CTRL_RLFW   = 0x6b,
 +      NM_ATT_BS11_ENA_RXLEV_HO        = 0x6c,
 +      NM_ATT_BS11_ENA_RXQUAL_HO       = 0x6d,
 +      NM_ATT_BS11_FACCH_QUAL          = 0x6e,
 +
 +      NM_ATT_IPACC_DST_IP             = 0x80,
 +      NM_ATT_IPACC_DST_IP_PORT        = 0x81,
 +      NM_ATT_IPACC_SSRC               = 0x82,
 +      NM_ATT_IPACC_RTP_PAYLD_TYPE     = 0x83,
 +      NM_ATT_IPACC_BASEB_ID           = 0x84,
 +      NM_ATT_IPACC_STREAM_ID          = 0x85,
 +      NM_ATT_IPACC_NV_FLAGS           = 0x86,
 +      NM_ATT_IPACC_FREQ_CTRL          = 0x87,
 +      NM_ATT_IPACC_PRIM_OML_CFG       = 0x88,
 +      NM_ATT_IPACC_SEC_OML_CFG        = 0x89,
 +      NM_ATT_IPACC_IP_IF_CFG          = 0x8a,         /* IP interface */
 +      NM_ATT_IPACC_IP_GW_CFG          = 0x8b,         /* IP gateway */
 +      NM_ATT_IPACC_IN_SERV_TIME       = 0x8c,
 +      NM_ATT_IPACC_TRX_BTS_ASS        = 0x8d,
 +      NM_ATT_IPACC_LOCATION           = 0x8e,         /* string describing location */
 +      NM_ATT_IPACC_PAGING_CFG         = 0x8f,
 +      NM_ATT_IPACC_FILE_DATA          = 0x90,
 +      NM_ATT_IPACC_UNIT_ID            = 0x91,         /* Site/BTS/TRX */
 +      NM_ATT_IPACC_PARENT_UNIT_ID     = 0x92,
 +      NM_ATT_IPACC_UNIT_NAME          = 0x93,         /* default: nbts-<mac-as-string> */
 +      NM_ATT_IPACC_SNMP_CFG           = 0x94,
 +      NM_ATT_IPACC_PRIM_OML_CFG_LIST  = 0x95,
 +      NM_ATT_IPACC_PRIM_OML_FB_TOUT   = 0x96,
 +      NM_ATT_IPACC_CUR_SW_CFG         = 0x97,
 +      NM_ATT_IPACC_TIMING_BUS         = 0x98,
 +      NM_ATT_IPACC_CGI                = 0x99,
 +      NM_ATT_IPACC_RAC                = 0x9a,
 +      NM_ATT_IPACC_OBJ_VERSION        = 0x9b,
 +      NM_ATT_IPACC_GPRS_PAGING_CFG    = 0x9c,
 +      NM_ATT_IPACC_NSEI               = 0x9d,
 +      NM_ATT_IPACC_BVCI               = 0x9e,
 +      NM_ATT_IPACC_NSVCI              = 0x9f,
 +      NM_ATT_IPACC_NS_CFG             = 0xa0,
 +      NM_ATT_IPACC_BSSGP_CFG          = 0xa1,
 +      NM_ATT_IPACC_NS_LINK_CFG        = 0xa2,
 +      NM_ATT_IPACC_RLC_CFG            = 0xa3, 
 +      NM_ATT_IPACC_ALM_THRESH_LIST    = 0xa4,
 +      NM_ATT_IPACC_MONIT_VAL_LIST     = 0xa5,
 +      NM_ATT_IPACC_TIB_CONTROL        = 0xa6,
 +      NM_ATT_IPACC_SUPP_FEATURES      = 0xa7,
 +      NM_ATT_IPACC_CODING_SCHEMES     = 0xa8,
 +      NM_ATT_IPACC_RLC_CFG_2          = 0xa9,
 +      NM_ATT_IPACC_HEARTB_TOUT        = 0xaa,
 +      NM_ATT_IPACC_UPTIME             = 0xab,
 +      NM_ATT_IPACC_RLC_CFG_3          = 0xac,
 +      NM_ATT_IPACC_SSL_CFG            = 0xad,
 +      NM_ATT_IPACC_SEC_POSSIBLE       = 0xae,
 +      NM_ATT_IPACC_IML_SSL_STATE      = 0xaf,
 +      NM_ATT_IPACC_REVOC_DATE         = 0xb0,
 +
 +
 +      NM_ATT_BS11_RF_RES_IND_PER      = 0x8f,
 +      
 +      NM_ATT_BS11_RX_LEV_MIN_CELL     = 0x90,
 +      NM_ATT_BS11_ABIS_EXT_TIME       = 0x91,
 +      NM_ATT_BS11_TIMER_HO_REQUEST    = 0x92,
 +      NM_ATT_BS11_TIMER_NCELL         = 0x93,
 +      NM_ATT_BS11_TSYNC               = 0x94,
 +      NM_ATT_BS11_TTRAU               = 0x95,
 +      NM_ATT_BS11_EMRG_CFG_MEMBER     = 0x9b,
 +      NM_ATT_BS11_TRX_AREA            = 0x9f,
 +
 +      NM_ATT_BS11_BCCH_RECONF         = 0xd7,
 +      NM_ATT_BS11_BIT_ERR_THESH       = 0xa0,
 +      NM_ATT_BS11_BOOT_SW_VERS        = 0xa1,
 +      NM_ATT_BS11_CCLK_ACCURACY       = 0xa3,
 +      NM_ATT_BS11_CCLK_TYPE           = 0xa4,
 +      NM_ATT_BS11_INP_IMPEDANCE       = 0xaa,
 +      NM_ATT_BS11_L1_PROT_TYPE        = 0xab,
 +      NM_ATT_BS11_LINE_CFG            = 0xac,
 +      NM_ATT_BS11_LI_PORT_1           = 0xad,
 +      NM_ATT_BS11_LI_PORT_2           = 0xae,
 +
 +      NM_ATT_BS11_L1_REM_ALM_TYPE     = 0xb0,
 +      NM_ATT_BS11_SW_LOAD_INTENDED    = 0xbb,
 +      NM_ATT_BS11_SW_LOAD_SAFETY      = 0xbc,
 +      NM_ATT_BS11_SW_LOAD_STORED      = 0xbd,
 +
 +      NM_ATT_BS11_VENDOR_NAME         = 0xc1,
 +      NM_ATT_BS11_HOPPING_MODE        = 0xc5,
 +      NM_ATT_BS11_LMT_LOGON_SESSION   = 0xc6,
 +      NM_ATT_BS11_LMT_LOGIN_TIME      = 0xc7,
 +      NM_ATT_BS11_LMT_USER_ACC_LEV    = 0xc8,
 +      NM_ATT_BS11_LMT_USER_NAME       = 0xc9,
 +
 +      NM_ATT_BS11_L1_CONTROL_TS       = 0xd8,
 +      NM_ATT_BS11_RADIO_MEAS_GRAN     = 0xdc, /* in SACCH multiframes */
 +      NM_ATT_BS11_RADIO_MEAS_REP      = 0xdd,
 +
 +      NM_ATT_BS11_SH_LAPD_INT_TIMER   = 0xe8,
 +
 +      NM_ATT_BS11_BTS_STATE           = 0xf0,
 +      NM_ATT_BS11_E1_STATE            = 0xf1,
 +      NM_ATT_BS11_PLL                 = 0xf2,
 +      NM_ATT_BS11_RX_OFFSET           = 0xf3,
 +      NM_ATT_BS11_ANT_TYPE            = 0xf4,
 +      NM_ATT_BS11_PLL_MODE            = 0xfc,
 +      NM_ATT_BS11_PASSWORD            = 0xfd,
 +};
 +#define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE
 +
 +/* Section 9.4.4: Administrative State */
 +enum abis_nm_adm_state {
 +      NM_STATE_LOCKED         = 0x01,
 +      NM_STATE_UNLOCKED       = 0x02,
 +      NM_STATE_SHUTDOWN       = 0x03,
 +      NM_STATE_NULL           = 0xff,
 +};
 +
 +/* Section 9.4.7: Administrative State */
 +enum abis_nm_avail_state {
 +      NM_AVSTATE_IN_TEST      = 1,
 +      NM_AVSTATE_POWER_OFF    = 2,
 +      NM_AVSTATE_OFF_LINE     = 3,
 +      NM_AVSTATE_DEPENDENCY   = 5,
 +      NM_AVSTATE_DEGRADED     = 6,
 +      NM_AVSTATE_NOT_INSTALLED= 7,
 +      NM_AVSTATE_OK           = 0xff,
 +};
 +
 +enum abis_nm_op_state {
 +      NM_OPSTATE_DISABLED     = 1,
 +      NM_OPSTATE_ENABLED      = 2,
 +      NM_OPSTATE_NULL         = 0xff,
 +};
 +
 +/* Section 9.4.13: Channel Combination */
 +enum abis_nm_chan_comb {
 +      NM_CHANC_TCHFull        = 0x00, /* TCH/F + TCH/H + SACCH/TF */
 +      NM_CHANC_TCHHalf        = 0x01, /* TCH/H(0,1) + FACCH/H(0,1) +
 +                                         SACCH/TH(0,1) */
 +      NM_CHANC_TCHHalf2       = 0x02, /* TCH/H(0) + FACCH/H(0) + SACCH/TH(0) +
 +                                         TCH/H(1) */
 +      NM_CHANC_SDCCH          = 0x03, /* SDCCH/8 + SACCH/8 */
 +      NM_CHANC_mainBCCH       = 0x04, /* FCCH + SCH + BCCH + CCCH */
 +      NM_CHANC_BCCHComb       = 0x05, /* FCCH + SCH + BCCH + CCCH + SDCCH/4 +
 +                                         SACCH/C4 */
 +      NM_CHANC_BCCH           = 0x06, /* BCCH + CCCH */
 +      NM_CHANC_BCCH_CBCH      = 0x07, /* CHANC_BCCHComb + CBCH */
 +      NM_CHANC_SDCCH_CBCH     = 0x08, /* CHANC_SDCCH8 + CBCH */
 +      /* ip.access */
 +      NM_CHANC_IPAC_bPDCH     = 0x0b, /* PBCCH + PCCCH + PDTCH/F + PACCH/F +
 +                                         PTCCH/F */
 +      NM_CHANC_IPAC_cPDCH     = 0x0c, /* PBCCH + PDTCH/F + PACCH/F + PTCCH/F */
 +      NM_CHANC_IPAC_PDCH      = 0x0d, /* PDTCH/F + PACCH/F + PTCCH/F */
 +      NM_CHANC_IPAC_TCHFull_PDCH = 0x80,
 +      NM_CHANC_IPAC_TCHFull_TCHHalf = 0x81,
 +};
 +
 +/* Section 9.4.16: Event Type */
 +enum abis_nm_event_type {
 +      NM_EVT_COMM_FAIL        = 0x00,
 +      NM_EVT_QOS_FAIL         = 0x01,
 +      NM_EVT_PROC_FAIL        = 0x02,
 +      NM_EVT_EQUIP_FAIL       = 0x03,
 +      NM_EVT_ENV_FAIL         = 0x04,
 +};
 +
 +/* Section: 9.4.63: Perceived Severity */
 +enum abis_nm_severity {
 +      NM_SEVER_CEASED         = 0x00,
 +      NM_SEVER_CRITICAL       = 0x01,
 +      NM_SEVER_MAJOR          = 0x02,
 +      NM_SEVER_MINOR          = 0x03,
 +      NM_SEVER_WARNING        = 0x04,
 +      NM_SEVER_INDETERMINATE  = 0x05,
 +};
 +
 +/* Section 9.4.43: Probable Cause Type */
 +enum abis_nm_pcause_type {
 +      NM_PCAUSE_T_X721        = 0x01,
 +      NM_PCAUSE_T_GSM         = 0x02,
 +      NM_PCAUSE_T_MANUF       = 0x03,
 +};
 +
 +/* Section 9.4.36: NACK Causes */
 +enum abis_nm_nack_cause {
 +      /* General Nack Causes */
 +      NM_NACK_INCORR_STRUCT           = 0x01,
 +      NM_NACK_MSGTYPE_INVAL           = 0x02,
 +      NM_NACK_OBJCLASS_INVAL          = 0x05,
 +      NM_NACK_OBJCLASS_NOTSUPP        = 0x06,
 +      NM_NACK_BTSNR_UNKN              = 0x07,
 +      NM_NACK_TRXNR_UNKN              = 0x08,
 +      NM_NACK_OBJINST_UNKN            = 0x09,
 +      NM_NACK_ATTRID_INVAL            = 0x0c,
 +      NM_NACK_ATTRID_NOTSUPP          = 0x0d,
 +      NM_NACK_PARAM_RANGE             = 0x0e,
 +      NM_NACK_ATTRLIST_INCONSISTENT   = 0x0f,
 +      NM_NACK_SPEC_IMPL_NOTSUPP       = 0x10,
 +      NM_NACK_CANT_PERFORM            = 0x11,
 +      /* Specific Nack Causes */
 +      NM_NACK_RES_NOTIMPL             = 0x19,
 +      NM_NACK_RES_NOTAVAIL            = 0x1a,
 +      NM_NACK_FREQ_NOTAVAIL           = 0x1b,
 +      NM_NACK_TEST_NOTSUPP            = 0x1c,
 +      NM_NACK_CAPACITY_RESTR          = 0x1d,
 +      NM_NACK_PHYSCFG_NOTPERFORM      = 0x1e,
 +      NM_NACK_TEST_NOTINIT            = 0x1f,
 +      NM_NACK_PHYSCFG_NOTRESTORE      = 0x20,
 +      NM_NACK_TEST_NOSUCH             = 0x21,
 +      NM_NACK_TEST_NOSTOP             = 0x22,
 +      NM_NACK_MSGINCONSIST_PHYSCFG    = 0x23,
 +      NM_NACK_FILE_INCOMPLETE         = 0x25,
 +      NM_NACK_FILE_NOTAVAIL           = 0x26,
 +      NM_NACK_FILE_NOTACTIVATE        = 0x27,
 +      NM_NACK_REQ_NOT_GRANT           = 0x28,
 +      NM_NACK_WAIT                    = 0x29,
 +      NM_NACK_NOTH_REPORT_EXIST       = 0x2a,
 +      NM_NACK_MEAS_NOTSUPP            = 0x2b,
 +      NM_NACK_MEAS_NOTSTART           = 0x2c,
 +};
 +
 +/* Section 9.4.1 */
 +struct abis_nm_channel {
 +      uint8_t attrib;
 +      uint8_t bts_port;
 +      uint8_t timeslot;
 +      uint8_t subslot;
 +} __attribute__ ((packed));
 +
 +/* Siemens BS-11 specific objects in the SienemsHW (0xA5) object class */
 +enum abis_bs11_objtype {
 +      BS11_OBJ_ALCO           = 0x01,
 +      BS11_OBJ_BBSIG          = 0x02, /* obj_class: 0,1 */
 +      BS11_OBJ_TRX1           = 0x03, /* only DEACTIVATE TRX1 */
 +      BS11_OBJ_CCLK           = 0x04,
 +      BS11_OBJ_GPSU           = 0x06,
 +      BS11_OBJ_LI             = 0x07,
 +      BS11_OBJ_PA             = 0x09, /* obj_class: 0, 1*/
 +};
 +
 +enum abis_bs11_trx_power {
 +      BS11_TRX_POWER_GSM_2W   = 0x06,
 +      BS11_TRX_POWER_GSM_250mW= 0x07,
 +      BS11_TRX_POWER_GSM_80mW = 0x08,
 +      BS11_TRX_POWER_GSM_30mW = 0x09,
 +      BS11_TRX_POWER_DCS_3W   = 0x0a,
 +      BS11_TRX_POWER_DCS_1W6  = 0x0b,
 +      BS11_TRX_POWER_DCS_500mW= 0x0c,
 +      BS11_TRX_POWER_DCS_160mW= 0x0d,
 +};
 +
 +enum abis_bs11_li_pll_mode {
 +      BS11_LI_PLL_LOCKED      = 2,
 +      BS11_LI_PLL_STANDALONE  = 3,
 +};
 +
 +enum abis_bs11_line_cfg {
 +      BS11_LINE_CFG_STAR      = 0x00,
 +      BS11_LINE_CFG_MULTIDROP = 0x01,
 +      BS11_LINE_CFG_LOOP      = 0x02,
 +};
 +
 +enum abis_bs11_phase {
 +      BS11_STATE_SOFTWARE_RQD         = 0x01,
 +      BS11_STATE_LOAD_SMU_INTENDED    = 0x11,
 +      BS11_STATE_LOAD_SMU_SAFETY      = 0x21,
 +      BS11_STATE_LOAD_FAILED          = 0x31,
 +      BS11_STATE_LOAD_DIAGNOSTIC      = 0x41,
 +      BS11_STATE_WARM_UP              = 0x51,
 +      BS11_STATE_WARM_UP_2            = 0x52,
 +      BS11_STATE_WAIT_MIN_CFG         = 0x62,
 +      BS11_STATE_MAINTENANCE          = 0x72,
 +      BS11_STATE_LOAD_MBCCU           = 0x92,
 +      BS11_STATE_WAIT_MIN_CFG_2       = 0xA2,
 +      BS11_STATE_NORMAL               = 0x03,
 +      BS11_STATE_ABIS_LOAD            = 0x13,
 +};
 +
 +enum abis_nm_ipacc_test_no {
 +      NM_IPACC_TESTNO_RLOOP_ANT       = 0x01,
 +      NM_IPACC_TESTNO_RLOOP_XCVR      = 0x02,
 +      NM_IPACC_TESTNO_FUNC_OBJ        = 0x03,
 +      NM_IPACC_TESTNO_CHAN_USAGE      = 0x40,
 +      NM_IPACC_TESTNO_BCCH_CHAN_USAGE = 0x41,
 +      NM_IPACC_TESTNO_FREQ_SYNC       = 0x42,
 +      NM_IPACC_TESTNO_BCCH_INFO       = 0x43,
 +      NM_IPACC_TESTNO_TX_BEACON       = 0x44,
 +      NM_IPACC_TESTNO_SYSINFO_MONITOR = 0x45,
 +      NM_IPACC_TESTNO_BCCCH_MONITOR   = 0x46,
 +};
 +
 +/* first byte after length inside NM_ATT_TEST_REPORT */
 +enum abis_nm_ipacc_test_res {
 +      NM_IPACC_TESTRES_SUCCESS        = 0,
 +      NM_IPACC_TESTRES_TIMEOUT        = 1,
 +      NM_IPACC_TESTRES_NO_CHANS       = 2,
 +      NM_IPACC_TESTRES_PARTIAL        = 3,
 +      NM_IPACC_TESTRES_STOPPED        = 4,
 +};
 +
 +/* internal IE inside NM_ATT_TEST_REPORT */
 +enum abis_nm_ipacc_testres_ie {
 +      NM_IPACC_TR_IE_FREQ_ERR_LIST    = 3,
 +      NM_IPACC_TR_IE_CHAN_USAGE       = 4,
 +      NM_IPACC_TR_IE_BCCH_INFO        = 6,
 +      NM_IPACC_TR_IE_RESULT_DETAILS   = 8,
 +      NM_IPACC_TR_IE_FREQ_ERR         = 18,
 +};
 +
 +enum ipac_eie {
 +      NM_IPAC_EIE_ARFCN_WHITE         = 0x01,
 +      NM_IPAC_EIE_ARFCH_BLACK         = 0x02,
 +      NM_IPAC_EIE_FREQ_ERR_LIST       = 0x03,
 +      NM_IPAC_EIE_CHAN_USE_LIST       = 0x04,
 +      NM_IPAC_EIE_BCCH_INFO_TYPE      = 0x05,
 +      NM_IPAC_EIE_BCCH_INFO           = 0x06,
++      NM_IPAC_EIE_CONFIG              = 0x07,
++      NM_IPAC_EIE_RES_DETAILS         = 0x08,
++      NM_IPAC_EIE_RXLEV_THRESH        = 0x09,
++      NM_IPAC_EIE_FREQ_SYNC_OPTS      = 0x0a,
++      NM_IPAC_EIE_MAC_ADDR            = 0x0b,
++      NM_IPAC_EIE_HW_SW_COMPAT_NR     = 0x0c,
++      NM_IPAC_EIE_MANUF_SER_NR        = 0x0d,
++      NM_IPAC_EIE_OEM_ID              = 0x0e,
++      NM_IPAC_EIE_DATE_TIME_MANUF     = 0x0f,
++      NM_IPAC_EIE_DATE_TIME_CALIB     = 0x10,
++      NM_IPAC_EIE_BEACON_INFO         = 0x11,
++      NM_IPAC_EIE_FREQ_ERR            = 0x12,
 +      /* FIXME */
++      NM_IPAC_EIE_FREQ_BANDS          = 0x1c,
++      NM_IPAC_EIE_MAX_TA              = 0x1d,
++      NM_IPAC_EIE_CIPH_ALGOS          = 0x1e,
++      NM_IPAC_EIE_CHAN_TYPES          = 0x1f,
++      NM_IPAC_EIE_CHAN_MODES          = 0x20,
++      NM_IPAC_EIE_GPRS_CODING         = 0x21,
++      NM_IPAC_EIE_RTP_FEATURES        = 0x22,
++      NM_IPAC_EIE_RSL_FEATURES        = 0x23,
++      NM_IPAC_EIE_BTS_HW_CLASS        = 0x24,
++      NM_IPAC_EIE_BTS_ID              = 0x25,
 +};
 +
 +enum ipac_bcch_info_type {
 +      IPAC_BINF_RXLEV                 = (1 << 8),
 +      IPAC_BINF_RXQUAL                = (1 << 9),
 +      IPAC_BINF_FREQ_ERR_QUAL         = (1 << 10),
 +      IPAC_BINF_FRAME_OFFSET          = (1 << 11),
 +      IPAC_BINF_FRAME_NR_OFFSET       = (1 << 12),
 +      IPAC_BINF_BSIC                  = (1 << 13),
 +      IPAC_BINF_CGI                   = (1 << 14),
 +      IPAC_BINF_NEIGH_BA_SI2          = (1 << 15),
 +      IPAC_BINF_NEIGH_BA_SI2bis       = (1 << 0),
 +      IPAC_BINF_NEIGH_BA_SI2ter       = (1 << 1),
 +      IPAC_BINF_CELL_ALLOC            = (1 << 2),
 +};
 +
 +#endif /* PROTO_GSM_12_21_H */
index 0000000,0000000..415509d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++#ifndef _OSMOCORE_RXLEV_STATS_H
++#define _OSMOCORE_RXLEV_STATS_H
++
++#define NUM_RXLEVS 32
++#define NUM_ARFCNS 1024
++
++struct rxlev_stats {
++      /* the maximum number of ARFCN's is 1024, and there are 32 RxLevels,
++       * so in we keep one 1024bit-bitvec for each RxLev */
++      uint8_t rxlev_buckets[NUM_RXLEVS][NUM_ARFCNS/8];
++};
++
++void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev);
++
++/* get the next ARFCN that has the specified Rxlev */
++int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn);
++
++void rxlev_stat_reset(struct rxlev_stats *st);
++
++void rxlev_stat_dump(const struct rxlev_stats *st);
++
++#endif /* _OSMOCORE_RXLEV_STATS_H */
index b6826ea,0000000..9942452
mode 100644,000000..100644
--- /dev/null
@@@ -1,12 -1,0 +1,12 @@@
-                        write_queue.c utils.c rsl.c gsm48.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 = libosmocore.la
 +
 +libosmocore_la_SOURCES = msgb.c timer.c talloc.c select.c signal.c \
 +                       tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \
++                       write_queue.c utils.c rsl.c gsm48.c rxlev_stat.c
index 235c3ce,0000000..eb83ac6
mode 100644,000000..100644
--- /dev/null
@@@ -1,170 -1,0 +1,170 @@@
- enum bit_value bitvec_get_bit_pos(struct bitvec *bv, unsigned int bitnr)
 +/* bit vector utility routines */
 +
 +/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +
 +#include <errno.h>
 +#include <stdint.h>
 +
 +#include <osmocore/bitvec.h>
 +
 +#define BITNUM_FROM_COMP(byte, bit)   ((byte*8)+bit)
 +
 +static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
 +{
 +      unsigned int bytenum = bitnum / 8;
 +
 +      return bytenum;
 +}
 +
 +/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
 +static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
 +{
 +      int bitval;
 +
 +      switch (bit) {
 +      case ZERO:
 +              bitval = (0 << bitnum);
 +              break;
 +      case ONE:
 +              bitval = (1 << bitnum);
 +              break;
 +      case L:
 +              bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
 +              break;
 +      case H:
 +              bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
 +              break;
 +      default:
 +              return 0;
 +      }
 +      return bitval;
 +}
 +
 +/* check if the bit is 0 or 1 for a given position inside a bitvec */
- unsigned int bitvec_get_nth_set_bit(struct bitvec *bv, unsigned int n)
++enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
 +{
 +      unsigned int bytenum = bytenum_from_bitnum(bitnr);
 +      unsigned int bitnum = 7 - (bitnr % 8);
 +      uint8_t bitval;
 +
 +      if (bytenum >= bv->data_len)
 +              return -EINVAL;
 +
 +      bitval = bitval2mask(ONE, bitnum);
 +
 +      if (bv->data[bytenum] & bitval)
 +              return ONE;
 +
 +      return ZERO;
 +}
 +
 +/* get the Nth set bit inside the bit vector */
++unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
 +{
 +      unsigned int i, k = 0;
 +
 +      for (i = 0; i < bv->data_len*8; i++) {
 +              if (bitvec_get_bit_pos(bv, i) == ONE) {
 +                      k++;
 +                      if (k == n)
 +                              return i;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +/* set the bit at a given position inside a bitvec */
 +int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
 +                      enum bit_value bit)
 +{
 +      unsigned int bytenum = bytenum_from_bitnum(bitnr);
 +      unsigned int bitnum = 7 - (bitnr % 8);
 +      uint8_t bitval;
 +
 +      if (bytenum >= bv->data_len)
 +              return -EINVAL;
 +
 +      /* first clear the bit */
 +      bitval = bitval2mask(ONE, bitnum);
 +      bv->data[bytenum] &= ~bitval;
 +
 +      /* then set it to desired value */
 +      bitval = bitval2mask(bit, bitnum);
 +      bv->data[bytenum] |= bitval;
 +
 +      return 0;
 +}
 +
 +/* set the next bit inside a bitvec */
 +int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
 +{
 +      int rc;
 +
 +      rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
 +      if (!rc)
 +              bv->cur_bit++;
 +
 +      return rc;
 +}
 +
 +/* set multiple bits (based on array of bitvals) at current pos */
 +int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count)
 +{
 +      int i, rc;
 +
 +      for (i = 0; i < count; i++) {
 +              rc = bitvec_set_bit(bv, bits[i]);
 +              if (rc)
 +                      return rc;
 +      }
 +
 +      return 0;
 +}
 +
 +/* set multiple bits (based on numeric value) at current pos */
 +int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits)
 +{
 +      int i, rc;
 +
 +      for (i = 0; i < num_bits; i++) {
 +              int bit = 0;
 +              if (ui & (1 << (num_bits - i - 1)))
 +                      bit = 1;
 +              rc = bitvec_set_bit(bv, bit);
 +              if (rc)
 +                      return rc;
 +      }
 +
 +      return 0;
 +}
 +
 +/* pad all remaining bits up to num_bits */
 +int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
 +{
 +      unsigned int i;
 +
 +      for (i = bv->cur_bit; i <= up_to_bit; i++)
 +              bitvec_set_bit(bv, L);
 +
 +      return 0;
 +}
index 174b2d4,0000000..4ee137c
mode 100644,000000..100644
--- /dev/null
@@@ -1,270 -1,0 +1,361 @@@
-  * (C) 2009 by Harald Welte <laforge@gnumonks.org>
 +/*
 + * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
 + * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
++ * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
 + *
 + * All Rights Reserved
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License along
 + * with this program; if not, write to the Free Software Foundation, Inc.,
 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + *
 + */
 +
 +//#include <openbsc/gsm_data.h>
 +#include <osmocore/utils.h>
 +#include <osmocore/gsm_utils.h>
 +
 +#include <stdlib.h>
 +#include <stdint.h>
 +#include <string.h>
 +#include <stdio.h>
 +#include <errno.h>
 +#include <ctype.h>
 +
 +#include "../config.h"
 +
 +/* GSM 03.38 6.2.1 Charachter packing */
 +int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length)
 +{
 +      int i = 0;
 +      int l = 0;
 +
 +        /* FIXME: We need to account for user data headers here */
 +      i += l;
 +      for (; i < length; i ++)
 +              *(text ++) =
 +                      ((user_data[(i * 7 + 7) >> 3] <<
 +                        (7 - ((i * 7 + 7) & 7))) |
 +                       (user_data[(i * 7) >> 3] >>
 +                        ((i * 7) & 7))) & 0x7f;
 +      *text = '\0';
 +
 +      return i - l;
 +}
 +
 +
 +/* GSM 03.38 6.2.1 Charachter packing */
 +int gsm_7bit_encode(uint8_t *result, const char *data)
 +{
 +      int i,j = 0;
 +      unsigned char ch1, ch2;
 +      int shift = 0;
 +
 +      for ( i=0; i<strlen(data); i++ ) {
 +
 +              ch1 = data[i] & 0x7F;
 +              ch1 = ch1 >> shift;
 +              ch2 = data[(i+1)] & 0x7F;
 +              ch2 = ch2 << (7-shift);
 +
 +              ch1 = ch1 | ch2;
 +
 +              result[j++] = ch1;
 +
 +              shift++;
 +
 +              if ((shift == 7) && (i+1<strlen(data))) {
 +                      shift = 0;
 +                      i++;
 +              }
 +      }
 +
 +      return i;
 +}
 +
 +/* determine power control level for given dBm value, as indicated
 + * by the tables in chapter 4.1.1 of GSM TS 05.05 */
 +int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm)
 +{
 +      switch (band) {
 +      case GSM_BAND_450:
 +      case GSM_BAND_480:
 +      case GSM_BAND_750:
 +      case GSM_BAND_900:
 +      case GSM_BAND_810:
 +      case GSM_BAND_850:
 +              if (dbm >= 39)
 +                      return 0;
 +              else if (dbm < 5)
 +                      return 19;
 +              else {
 +                      /* we are guaranteed to have (5 <= dbm < 39) */
 +                      return 2 + ((39 - dbm) / 2);
 +              }
 +              break;
 +      case GSM_BAND_1800:
 +              if (dbm >= 36)
 +                      return 29;
 +              else if (dbm >= 34)     
 +                      return 30;
 +              else if (dbm >= 32)
 +                      return 31;
 +              else if (dbm == 31)
 +                      return 0;
 +              else {
 +                      /* we are guaranteed to have (0 <= dbm < 31) */
 +                      return (30 - dbm) / 2;
 +              }
 +              break;
 +      case GSM_BAND_1900:
 +              if (dbm >= 33)
 +                      return 30;
 +              else if (dbm >= 32)
 +                      return 31;
 +              else if (dbm == 31)
 +                      return 0;
 +              else {
 +                      /* we are guaranteed to have (0 <= dbm < 31) */
 +                      return (30 - dbm) / 2;
 +              }
 +              break;
 +      }
 +      return -EINVAL;
 +}
 +
 +int ms_pwr_dbm(enum gsm_band band, uint8_t lvl)
 +{
 +      lvl &= 0x1f;
 +
 +      switch (band) {
 +      case GSM_BAND_450:
 +      case GSM_BAND_480:
 +      case GSM_BAND_750:
 +      case GSM_BAND_900:
 +      case GSM_BAND_810:
 +      case GSM_BAND_850:
 +              if (lvl < 2)
 +                      return 39;
 +              else if (lvl < 20)
 +                      return 39 - ((lvl - 2) * 2) ;
 +              else
 +                      return 5;
 +              break;
 +      case GSM_BAND_1800:
 +              if (lvl < 16)
 +                      return 30 - (lvl * 2);
 +              else if (lvl < 29)
 +                      return 0;
 +              else
 +                      return 36 - ((lvl - 29) * 2);
 +              break;
 +      case GSM_BAND_1900:
 +              if (lvl < 16)
 +                      return 30 - (lvl * 2);
 +              else if (lvl < 30)
 +                      return -EINVAL;
 +              else
 +                      return 33 - (lvl - 30);
 +              break;
 +      }
 +      return -EINVAL;
 +}
 +
 +/* According to TS 08.05 Chapter 8.1.4 */
 +int rxlev2dbm(uint8_t rxlev)
 +{
 +      if (rxlev > 63)
 +              rxlev = 63;
 +
 +      return -110 + rxlev;
 +}
 +
 +/* According to TS 08.05 Chapter 8.1.4 */
 +uint8_t dbm2rxlev(int dbm)
 +{
 +      int rxlev = dbm + 110;
 +
 +      if (rxlev > 63)
 +              rxlev = 63;
 +      else if (rxlev < 0)
 +              rxlev = 0;
 +
 +      return rxlev;
 +}
 +
 +char *gsm_band_name(enum gsm_band band)
 +{
 +      switch (band) {
 +      case GSM_BAND_450:
 +              return "GSM450";
 +      case GSM_BAND_480:
 +              return "GSM450";
 +      case GSM_BAND_750:
 +              return "GSM750";
 +      case GSM_BAND_810:
 +              return "GSM810";
 +      case GSM_BAND_850:
 +              return "GSM850";
 +      case GSM_BAND_900:
 +              return "GSM900";
 +      case GSM_BAND_1800:
 +              return "DCS1800";
 +      case GSM_BAND_1900:
 +              return "PCS1900";
 +      }
 +      return "invalid";
 +}
 +
 +enum gsm_band gsm_band_parse(const char* mhz)
 +{
 +      while (*mhz && !isdigit(*mhz))
 +              mhz++;
 +
 +      if (*mhz == '\0')
 +              return -EINVAL;
 +
 +      switch (atoi(mhz)) {
 +      case 450:
 +              return GSM_BAND_450;
 +      case 480:
 +              return GSM_BAND_480;
 +      case 750:
 +              return GSM_BAND_750;
 +      case 810:
 +              return GSM_BAND_810;
 +      case 850:
 +              return GSM_BAND_850;
 +      case 900:
 +              return GSM_BAND_900;
 +      case 1800:
 +              return GSM_BAND_1800;
 +      case 1900:
 +              return GSM_BAND_1900;
 +      default:
 +              return -EINVAL;
 +      }
 +}
 +
 +
 +#ifdef HAVE_EXECINFO_H
 +#include <execinfo.h>
 +void generate_backtrace()
 +{
 +      int i, nptrs;
 +      void *buffer[100];
 +      char **strings;
 +
 +      nptrs = backtrace(buffer, ARRAY_SIZE(buffer));
 +      printf("backtrace() returned %d addresses\n", nptrs);
 +
 +      strings = backtrace_symbols(buffer, nptrs);
 +      if (!strings)
 +              return;
 +
 +      for (i = 1; i < nptrs; i++)
 +              printf("%s\n", strings[i]);
 +
 +      free(strings);
 +}
 +#endif
++
++enum gsm_band gsm_arfcn2band(uint16_t arfcn)
++{
++      if (arfcn & ARFCN_PCS)
++              return GSM_BAND_1900;
++      else if (arfcn <= 124)
++              return GSM_BAND_900;
++      else if (arfcn >= 955 && arfcn <= 1023)
++              return GSM_BAND_900;
++      else if (arfcn >= 128 && arfcn <= 251)
++              return GSM_BAND_850;
++      else if (arfcn >= 512 && arfcn <= 885)
++              return GSM_BAND_1800;
++      else if (arfcn >= 259 && arfcn <= 293)
++              return GSM_BAND_450;
++      else if (arfcn >= 306 && arfcn <= 340)
++              return GSM_BAND_480;
++      else if (arfcn >= 350 && arfcn <= 425)
++              return GSM_BAND_810;
++      else if (arfcn >= 438 && arfcn <= 511)
++              return GSM_BAND_750;
++      else
++              return GSM_BAND_1800;
++}
++
++/* Convert an ARFCN to the frequency in MHz * 10 */
++uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink)
++{
++      uint16_t freq10_ul;
++      uint16_t freq10_dl;
++
++      if (arfcn & ARFCN_PCS) {
++              /* DCS 1900 */
++              arfcn &= ~ARFCN_PCS;
++              freq10_ul = 18502 + 2 * (arfcn-512);
++              freq10_dl = freq10_ul + 800;
++      } else if (arfcn <= 124) {
++              /* Primary GSM + ARFCN 0 of E-GSM */
++              freq10_ul = 8900 + 2 * arfcn;
++              freq10_dl = freq10_ul + 450;
++      } else if (arfcn >= 955 && arfcn <= 1023) {
++              /* E-GSM and R-GSM */
++              freq10_ul = 8900 + 2 * (arfcn - 1024);
++              freq10_dl = freq10_ul + 450;
++      } else if (arfcn >= 128 && arfcn <= 251) {
++              /* GSM 850 */
++              freq10_ul = 8242 + 2 * (arfcn - 128);
++              freq10_dl = freq10_ul + 450;
++      } else if (arfcn >= 512 && arfcn <= 885) {
++              /* DCS 1800 */
++              freq10_ul = 17102 + 2 * (arfcn - 512);
++              freq10_dl = freq10_ul + 950;
++      } else if (arfcn >= 259 && arfcn <= 293) {
++              /* GSM 450 */
++              freq10_ul = 4506 + 2 * (arfcn - 259);
++              freq10_dl = freq10_ul + 100;
++      } else if (arfcn >= 306 && arfcn <= 340) {
++              /* GSM 480 */
++              freq10_ul = 4790 + 2 * (arfcn - 306);
++              freq10_dl = freq10_ul + 100;
++      } else if (arfcn >= 350 && arfcn <= 425) {
++              /* GSM 810 */
++              freq10_ul = 8060 + 2 * (arfcn - 350);
++              freq10_dl = freq10_ul + 450;
++      } else if (arfcn >= 438 && arfcn <= 511) {
++              /* GSM 750 */
++              freq10_ul = 7472 + 2 * (arfcn - 438);
++              freq10_dl = freq10_ul + 300;
++      } else
++              return 0xffff;
++
++      if (uplink)
++              return freq10_ul;
++      else
++              return freq10_dl;
++}
++
++void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn)
++{
++      time->fn = fn;
++      time->t1 = time->fn / (26*51);
++      time->t2 = time->fn % 26;
++      time->t3 = time->fn % 51;
++      time->tc = (time->fn / 51) % 8;
++}
++
++uint32_t gsm_gsmtime2fn(struct gsm_time *time)
++{
++      /* TS 05.02 Chapter 4.3.3 TDMA frame number */
++      return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1));
++}
index 0000000,0000000..1bfd679
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,94 @@@
++/* Rx Level statistics */
++
++/* (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 <unistd.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <stdint.h>
++
++#include <osmocore/bitvec.h>
++#include <osmocore/rxlev_stat.h>
++
++int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value val)
++{
++      unsigned int i;
++
++      for (i = n; i < bv->data_len*8; i++) {
++              if (bitvec_get_bit_pos(bv, i) == val)
++                      return i;
++      }
++
++      return -1;
++}
++
++void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev)
++{
++      struct bitvec bv;
++
++      if (rxlev >= NUM_RXLEVS)
++              rxlev = NUM_RXLEVS-1;
++
++      bv.data_len = NUM_ARFCNS/8;
++      bv.data = st->rxlev_buckets[rxlev];
++
++      bitvec_set_bit_pos(&bv, arfcn, ONE);
++}
++
++/* get the next ARFCN that has the specified Rxlev */
++int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn)
++{
++      struct bitvec bv;
++
++      if (rxlev >= NUM_RXLEVS)
++              rxlev = NUM_RXLEVS-1;
++
++      bv.data_len = NUM_ARFCNS/8;
++
++      if (arfcn < 0)
++              arfcn = -1;
++
++      bv.data = st->rxlev_buckets[rxlev];
++
++      return bitvec_find_bit_pos(&bv, arfcn+1, ONE);
++}
++
++void rxlev_stat_reset(struct rxlev_stats *st)
++{
++      memset(st, 0, sizeof(*st));
++}
++
++void rxlev_stat_dump(const struct rxlev_stats *st)
++{
++      int i;
++
++      for (i = NUM_RXLEVS-1; i >= 0; i--) {
++              int16_t arfcn = -1;
++
++              printf("ARFCN with RxLev %u: ", i);
++              while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) {
++                      printf("%u ", arfcn);
++              }
++              printf("\n");
++      }
++}