initial commit of current OpenBSC state

diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h
new file mode 100644
index 0000000..1108aa4
--- /dev/null
+++ b/include/openbsc/abis_nm.h
@@ -0,0 +1,316 @@
+/* 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 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 _NM_H
+#define _NM_H
+
+#include <sys/types.h>
+
+/* PRIVATE */
+
+/* generic header in front of every OML message */
+struct abis_om_hdr {
+	u_int8_t	mdisc;
+	u_int8_t	placement;
+	u_int8_t	sequence;
+	u_int8_t	length;
+	u_int8_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 {
+	u_int8_t	bts_nr;
+	u_int8_t	trx_nr;
+	u_int8_t	ts_nr;
+} __attribute__ ((packed));
+
+struct abis_om_fom_hdr {
+	u_int8_t	msg_type;
+	u_int8_t	obj_class;
+	struct abis_om_obj_inst	obj_inst;
+} __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_TESET_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,
+	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,
+};
+
+/* Section 9.2: Object Class */
+enum abis_nm_obj_class {
+	NM_OC_SITE_MANAGER		= 0x00,
+	NM_OC_BTS,
+	NM_OC_RADIO_CARRIER,
+	NM_OC_BASEB_TRANSC,
+	NM_OC_CHANNEL,
+	/* RFU: 05-FE */
+	NM_OC_NULL			= 0xff,
+};
+
+/* Section 9.4: Attributes */
+enum abis_nm_attr {
+	NM_ATT_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,
+	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_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,
+};
+
+/* 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.13: Channel Combination */
+enum abis_nm_chan_comb {
+	NM_CHANC_TCHFull	= 0x00,
+	NM_CHANC_TCHHalf	= 0x01,
+	NM_CHANC_TCHHalf2	= 0x02,
+	NM_CHANC_SDCCH		= 0x03,
+	NM_CHANC_mainBCCH	= 0x04,
+	NM_CHANC_BCCCHComb	= 0x05,
+	NM_CHANC_BCCH		= 0x06,
+	NM_CHANC_BCCH_CBCH	= 0x07,
+	NM_CHANC_SDCCH_CBCH	= 0x08,
+};
+
+/* Section 9.4.1 */
+struct abis_nm_abis_channel {
+	u_int8_t	attrib;
+	u_int8_t	bts_port;
+	u_int8_t	timeslot;
+	u_int8_t	subslot;
+} __attribute__ ((packed));
+
+/* PUBLIC */
+
+struct msgb;
+
+struct abis_nm_cfg {
+	/* callback for unidirectional reports */
+	int (*report_cb)(struct msgb *,
+			 struct abis_om_fom_hdr *);
+	/* callback for software activate requests from BTS */
+	int (*sw_act_req)(struct msgb *);
+};
+
+extern int abis_nm_rx(struct msgb *msg);
+//extern struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg);
+//extern void abis_nm_fini(struct abis_nm_h *nmh);
+
+int abis_nm_rx(struct msgb *msg);
+int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
+			  u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
+			  u_int8_t tei);
+int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
+			   u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot);
+int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
+			   u_int8_t e1_port, u_int8_t e1_timeslot,
+			   u_int8_t e1_subslot);
+int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb);
+int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg);
+int abis_nm_event_reports(struct gsm_bts *bts, int on);
+int abis_nm_reset_resource(struct gsm_bts *bts);
+int abis_nm_db_transaction(struct gsm_bts *bts, int begin);
+
+#endif /* _NM_H */
diff --git a/include/openbsc/abis_rsl.h b/include/openbsc/abis_rsl.h
new file mode 100644
index 0000000..9413f65
--- /dev/null
+++ b/include/openbsc/abis_rsl.h
@@ -0,0 +1,303 @@
+/* GSM Radio Signalling Link messages on the A-bis interface 
+ * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
+
+/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef _RSL_H
+#define _RSL_H
+
+struct abis_rsl_common_hdr {
+	u_int8_t	msg_discr;
+	u_int8_t	msg_type;
+	u_int8_t	data[0];
+} __attribute__ ((packed));
+
+/* Chapter 8.3 */
+struct abis_rsl_rll_hdr {
+	struct abis_rsl_common_hdr c;
+	u_int8_t	ie_chan;
+	u_int8_t	chan_nr;
+	u_int8_t	ie_link_id;
+	u_int8_t	link_id;
+	u_int8_t	data[0];
+} __attribute__ ((packed));
+
+/* Chapter 8.3 and 8.4 */
+struct abis_rsl_dchan_hdr {
+	struct abis_rsl_common_hdr c;
+	u_int8_t	ie_chan;
+	u_int8_t	chan_nr;
+	u_int8_t	data[0];
+} __attribute__ ((packed));
+
+
+/* Chapter 9.1 */
+#define ABIS_RSL_MDISC_RLL		0x02
+#define ABIS_RSL_MDISC_DED_CHAN		0x08
+#define ABIS_RSL_MDISC_COM_CHAN		0x0c
+#define ABIS_RSL_MDISC_TRX		0x10
+#define ABIS_RSL_MDISC_LOC		0x20
+
+#define ABIS_RSL_MDISC_IS_TRANSP(x)	(x & 0x01)
+
+/* Chapter 9.2 */
+enum abis_rsl_msgtype {
+	/* Radio Link Layer Management */
+	RSL_MT_DATA_REQ			= 0x01,
+	RSL_MT_DATA_IND,
+	RSL_MT_ERROR_IND,
+	RSL_MT_EST_REQ,
+	RSL_MT_EST_CONF,
+	RSL_MT_EST_IND,
+	RSL_MT_REL_REQ,
+	RSL_MT_REL_CONF,
+	RSL_MT_REL_IND,
+	RSL_MT_UNIT_DATA_REQ,
+	RSL_MT_UNIT_DATA_IND,		/* 0x0b */
+
+	/* Common Channel Management / TRX Management */
+	RSL_MT_BCCH_INFO			= 0x11,
+	RSL_MT_CCCH_LOAD_IND,
+	RSL_MT_CHAN_RQD,
+	RSL_MT_DELETE_IND,
+	RSL_MT_PAGING_CMD,
+	RSL_MT_IMMEDIATE_ASSIGN_CMD,
+	RSL_MT_SMS_BC_REQ,
+	/* empty */
+	RSL_MT_RF_RES_IND			= 0x19,
+	RSL_MT_SACCH_FILL,
+	RSL_MT_OVERLOAD,
+	RSL_MT_ERROR_REPORT,
+	RSL_MT_SMS_BC_CMD,
+	RSL_MT_CBCH_LOAD_IND,
+	RSL_MT_NOT_CMD,			/* 0x1f */
+
+	/* Dedicate Channel Management */
+	RSL_MT_CHAN_ACTIV			= 0x21,
+	RSL_MT_CHAN_ACTIV_ACK,
+	RSL_MT_CHAN_ACTIV_NACK,
+	RSL_MT_CONN_FAIL,
+	RSL_MT_DEACTIVATE_SACCH,
+	RSL_MT_ENCR_CMD,
+	RSL_MT_HANDO_DET,
+	RSL_MT_MEAS_RES,
+	RSL_MT_MODE_MODIFY_REQ,
+	RSL_MT_MODE_MODIFY_ACK,
+	RSL_MT_MODE_MODIFY_NACK,
+	RSL_MT_PHY_CONTEXT_REQ,
+	RSL_MT_PHY_CONTEXT_CONF,
+	RSL_MT_RF_CHAN_REL,
+	RSL_MT_MS_POWER_CONTROL,
+	RSL_MT_BS_POWER_CONTROL,
+	RSL_MT_PREPROC_CONFIG,
+	RSL_MT_PREPROC_MEAS_RES,
+	RSL_MT_RF_CHAN_REL_ACK,
+	RSL_MT_SACCH_INFO_MODIFY,
+	RSL_MT_TALKER_DET,
+	RSL_MT_LISTENER_DET,
+	RSL_MT_REMOTE_CODEC_CONF_REP,
+	RSL_MT_RTD_REP,
+	RSL_MT_PRE_HANDO_NOTIF,
+	RSL_MT_MR_CODEC_MOD_REQ,
+	RSL_MT_MR_CODEC_MOD_ACK,
+	RSL_MT_MR_CODEC_MOD_NACK,
+	RSL_MT_MR_CODEC_MOD_PER,
+	RSL_MT_TFO_REP,
+	RSL_MT_TFO_MOD_REQ,		/* 0x3f */
+};
+
+/* Chapter 9.3 */
+enum abis_rsl_ie {
+	RSL_IE_CHAN_NR			= 0x01,
+	RSL_IE_LINK_IDENT,
+	RSL_IE_ACT_TYPE,
+	RSL_IE_BS_POWER,
+	RSL_IE_CHAN_IDENT,
+	RSL_IE_CHAN_MODE,
+	RSL_IE_ENCR_INFO,
+	RSL_IE_FRAME_NUMBER,
+	RSL_IE_HANDO_REF,
+	RSL_IE_L1_INFO,
+	RSL_IE_L3_INFO,
+	RSL_IE_MS_IDENTITY,
+	RSL_IE_MS_POWER,
+	RSL_IE_PAGING_GROUP,
+	RSL_IE_PAGING_LOAD,
+	RSL_IE_PYHS_CONTEXT		= 0x10,
+	RSL_IE_ACCESS_DELAY,
+	RSL_IE_RACH_LOAD,
+	RSL_IE_REQ_REFERENCE,
+	RSL_IE_RELEASE_MODE,
+	RSL_IE_RESOURCE_INFO,
+	RSL_IE_RLM_CAUSE,
+	RSL_IE_STARTNG_TIME,
+	RSL_IE_TIMING_ADVANCE,
+	RSL_IE_UPLINK_MEAS,
+	RSL_IE_CAUSE,
+	RSL_IE_MEAS_RES_NR,
+	RSL_IE_MSG_ID,
+	/* reserved */
+	RSL_IE_SYSINFO_TYPE		= 0x1e,
+	RSL_IE_MS_POWER_PARAM,
+	RSL_IE_BS_POWER_PARAM,
+	RSL_IE_PREPROC_PARAM,
+	RSL_IE_PREPROC_MEAS,
+	RSL_IE_IMM_ASS_INFO,		/* Phase 1 (3.6.0), later Full below */
+	RSL_IE_SMSCB_INFO		= 0x24,
+	RSL_IE_MS_TIMING_OFFSET,
+	RSL_IE_ERR_MSG,
+	RSL_IE_FULL_BCCH_INFO,
+	RSL_IE_CHAN_NEEDED,
+	RSL_IE_CB_CMD_TYPE,
+	RSL_IE_SMSCB_MSG,
+	RSL_IE_FULL_IMM_ASS_INFO,
+	RSL_IE_SACCH_INFO,
+	RSL_IE_CBCH_LOAD_INFO,
+	RSL_IE_SMSCB_CHAN_INDICATOR,
+	RSL_IE_GROUP_CALL_REF,
+	RSL_IE_CHAN_DESC,
+	RSL_IE_NCH_DRX_INFO,
+	RSL_IE_CMD_INDICATOR,
+	RSL_IE_EMLPP_PRIO,
+	RSL_IE_UIC,
+	RSL_IE_MAIN_CHAN_REF,
+	RSL_IE_MR_CONFIG,
+	RSL_IE_MR_CONTROL,
+	RSL_IE_SUP_CODEC_TYPES,
+	RSL_IE_CODEC_CONFIG,
+	RSL_IE_RTD,
+	RSL_IE_TFO_STATUS,
+	RSL_IE_LLP_APDU,
+};
+
+/* Chapter 9.3.1 */
+#define RSL_CHAN_NR_MASK	0xf8
+#define RSL_CHAN_Bm_ACCHs	0x08
+#define RSL_CHAN_Lm_ACCHs	0x10	/* .. 0x18 */
+#define RSL_CHAN_SDCCH4_ACCH	0x20	/* .. 0x38 */
+#define RSL_CHAN_SDCCH8_ACCH	0x40	/* ...0x78 */
+#define RSL_CHAN_BCCH		0x80
+#define RSL_CHAN_RACH		0x88
+#define RSL_CHAN_PCH_AGCH	0x90
+
+/* Chapter 9.3.3 */
+#define RSL_ACT_TYPE_INITIAL	0x00
+#define RSL_ACT_TYPE_REACT	0x80
+#define RSL_ACT_INTRA_IMM_ASS	0x00
+#define RSL_ACT_INTRA_NORM_ASS	0x01
+#define RSL_ACT_INTER_ASYNC	0x02
+#define RSL_ACT_INTER_SYNC	0x03
+#define RSL_ACT_SECOND_ADD	0x04
+#define RSL_ACT_SECOND_MULTI	0x05
+
+/* Chapter 9.3.6 */
+struct rsl_ie_chan_mode {
+	u_int8_t dtx_dtu;
+	u_int8_t spd_ind;
+	u_int8_t chan_rt;
+	u_int8_t chan_rate;
+} __attribute__ ((packed));
+#define RSL_CMOD_DTXu		0x01	/* uplink */
+#define RSL_CMOD_DTXd		0x02	/* downlink */
+#define RSL_CMOD_SPD_SPEECH	0x01
+#define RSL_CMOD_SPD_DATA	0x02
+#define RSL_CMOD_SPD_SIGN	0x03
+#define RSL_CMOD_CRT_SDCCH	0x01
+#define RSL_CMOD_CRT_TCH_Bm	0x08	/* full-rate */
+#define RSL_CMOD_CRT_TCH_Lm	0x09	/* half-rate */
+/* FIXME: More CRT types */
+#define RSL_CMOD_SP_GSM1	0x01
+#define RSL_CMOD_SP_GSM2	0x11
+#define RSL_CMOD_SP_GSM3	0x21
+
+/* Chapter 9.3.5 */
+struct rsl_ie_chan_ident {
+	/* GSM 04.08 10.5.2.5 */
+	struct {
+		u_int8_t iei;
+		u_int8_t chan_nr;	/* enc_chan_nr */
+		u_int8_t oct3;
+		u_int8_t oct4;
+	} chan_desc;
+#if 0	/* spec says we need this but Abissim doesn't use it */
+	struct {
+		u_int8_t tag;
+		u_int8_t len;
+	} mobile_alloc;
+#endif
+} __attribute__ ((packed));
+
+/* Chapter 9.3.30 */
+#define RSL_SYSTEM_INFO_8	0x00
+#define RSL_SYSTEM_INFO_1	0x01
+#define RSL_SYSTEM_INFO_2	0x02
+#define RSL_SYSTEM_INFO_3	0x03
+#define RSL_SYSTEM_INFO_4	0x04
+#define RSL_SYSTEM_INFO_5	0x05
+#define RSL_SYSTEM_INFO_6	0x06
+#define RSL_SYSTEM_INFO_7	0x07
+#define RSL_SYSTEM_INFO_16	0x08
+#define RSL_SYSTEM_INFO_17	0x09
+#define RSL_SYSTEM_INFO_2bis	0x0a
+#define RSL_SYSTEM_INFO_2ter	0x0b
+#define RSL_SYSTEM_INFO_5bis	0x0d
+#define RSL_SYSTEM_INFO_5ter	0x0e
+#define RSL_SYSTEM_INFO_10	0x0f
+#define REL_EXT_MEAS_ORDER	0x47
+#define RSL_MEAS_INFO		0x48
+#define RSL_SYSTEM_INFO_13	0x28
+#define RSL_SYSTEM_INFO_2quater	0x29
+#define RSL_SYSTEM_INFO_9	0x2a
+#define RSL_SYSTEM_INFO_18	0x2b
+#define RSL_SYSTEM_INFO_19	0x2c
+#define RSL_SYSTEM_INFO_20	0x2d
+
+/* Chapter 9.3.40 */
+#define RSL_CHANNEED_ANY	0x00
+#define RSL_CHANNEED_SDCCH	0x01
+#define RSL_CHANNEED_TCH_F	0x02
+#define RSL_CHANNEED_TCH_ForH	0x03
+
+
+#include "msgb.h"
+
+int rsl_bcch_info(struct gsm_bts *bts, u_int8_t type,
+		  const u_int8_t *data, int len);
+int rsl_sacch_filling(struct gsm_bts *bts, u_int8_t type, 
+		      const u_int8_t *data, int len);
+int rsl_chan_activate(struct gsm_bts *bts, u_int8_t chan_nr,
+		      u_int8_t act_type,
+		      struct rsl_ie_chan_mode *chan_mode,
+		      struct rsl_ie_chan_ident *chan_ident,
+		      u_int8_t bs_power, u_int8_t ms_power,
+		      u_int8_t ta);
+int rsl_chan_activate_tch_f(struct gsm_bts_trx_ts *ts);
+int rsl_chan_activate_sdcch(struct gsm_bts_trx_ts *ts);
+int rsl_chan_release(struct gsm_bts_trx_ts *ts, u_int8_t chan_nr);
+int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len,
+		   u_int8_t *ms_ident, u_int8_t chan_needed);
+int rsl_paging_cmd_imsi(struct gsm_bts *bts, u_int8_t chan_needed, const char *imsi_str);
+int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val);
+int rsl_data_request(struct gsm_bts *bts, struct msgb *msg);
+
+int abis_rsl_rx(struct msgb *msg);
+
+#endif /* RSL_MT_H */
+
diff --git a/include/openbsc/debug.h b/include/openbsc/debug.h
new file mode 100644
index 0000000..c1db120
--- /dev/null
+++ b/include/openbsc/debug.h
@@ -0,0 +1,15 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#define DRLL		0x0001
+#define DCC		0x0002
+#define DMM		0x0004
+#define DRR		0x0008
+
+#ifdef DEBUG
+#define DEBUGP(ss, args, ...)	debugp(ss, args, ...)
+#else
+#define DEBUGP(xss, args, ...) 
+#endif
+
+#endif /* _DEBUG_H */
diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h
new file mode 100644
index 0000000..7c51969
--- /dev/null
+++ b/include/openbsc/gsm_04_08.h
@@ -0,0 +1,238 @@
+#ifndef _GSM_04_08_H
+#define _GSM_04_08_H
+
+/* GSM TS 04.08  definitions */
+
+/* Chapter 10.5.2.5 */
+struct gsm48_chan_desc {
+	u_int8_t chan_nr;
+	union {
+		struct {
+			u_int8_t maio_high:4,
+				 h:1,
+				 tsc:3;
+			u_int8_t hsn:6,
+				 maio_low:2;
+		} h1;
+		struct {
+			u_int8_t arfcn_high:2,
+				 spare:2,
+				 h:1,
+				 tsc:3;
+			u_int8_t arfcn_low;
+		} h0;
+	};
+};
+
+/* Chapter 10.5.2.30 */
+struct gsm48_req_ref {
+	u_int8_t ra;
+	u_int8_t t3_high:3,
+		 t1_:5;
+	u_int8_t t2:5,
+		 t3_low:3;
+};
+
+/* Chapter 9.1.18 */
+struct gsm48_imm_ass {
+	u_int8_t l2_plen;
+	u_int8_t proto_discr;
+	u_int8_t msg_type;
+	u_int8_t page_mode;
+	struct gsm48_chan_desc chan_desc;
+	struct gsm48_req_ref req_ref;
+	u_int8_t timing_advance;
+	u_int8_t mob_alloc_len;
+	u_int8_t mob_alloc[0];
+};
+
+struct gsm48_loc_area_id {
+	u_int8_t digits[3];	/* BCD! */
+	u_int16_t lac;
+} __attribute__ ((packed));
+
+/* Section 9.2.15 */
+struct gsm48_loc_upd_req {
+	u_int8_t type:4,
+		 key_seq:4;
+	struct gsm48_loc_area_id lai;
+	u_int8_t classmark1;
+	u_int8_t ie_mi;
+	u_int8_t mi_len;
+	u_int8_t mi[0];
+} __attribute__ ((packed));
+
+/* Section 10.1 */
+struct gsm48_hdr {
+	u_int8_t proto_discr;
+	u_int8_t msg_type;
+	u_int8_t data[0];
+} __attribute__ ((packed));
+
+/* Section 10.2 */
+#define GSM48_PDISC_CC		0x02
+#define GSM48_PDISC_MM		0x05
+#define GSM48_PDISC_RR		0x06
+#define GSM48_PDISC_MM_GPRS	0x08
+#define GSM48_PDISC_SM		0x0a
+
+/* Section 10.4 */
+#define GSM48_MT_RR_INIT_REQ		0x3c
+#define GSM48_MT_RR_ADD_ASS		0x3b
+#define GSM48_MT_RR_IMM_ASS		0x3f
+#define GSM48_MT_RR_IMM_ASS_EXT		0x39
+#define GSM48_MT_RR_IMM_ASS_REJ		0x3a
+
+#define GSM48_MT_RR_CIPH_M_CMD		0x35
+#define GSM48_MT_RR_CIPH_M_COMPL	0x32
+
+#define GSM48_MT_RR_CFG_CHG_CMD		0x30
+#define GSM48_MT_RR_CFG_CHG_ACK		0x31
+#define GSM48_MT_RR_CFG_CHG_REJ		0x33
+
+#define GSM48_MT_RR_ASS_CMD		0x2e
+#define GSM48_MT_RR_ASS_COMPL		0x29
+#define GSM48_MT_RR_ASS_FAIL		0x2f
+#define GSM48_MT_RR_HANDO_CMD		0x2b
+#define GSM48_MT_RR_HANDO_COMPL		0x2c
+#define GSM48_MT_RR_HANDO_FAIL		0x28
+#define GSM48_MT_RR_HANDO_INFO		0x2d
+
+#define GSM48_MT_RR_CELL_CHG_ORDER	0x08
+#define GSM48_MT_RR_PDCH_ASS_CMD	0x23
+
+#define GSM48_MT_RR_CHAN_REL		0x0d
+#define GSM48_MT_RR_PART_REL		0x0a
+#define GSM48_MT_RR_PART_REL_COMP	0x0f
+
+#define GSM48_MT_RR_PAG_REQ_1		0x21
+#define GSM48_MT_RR_PAG_REQ_2		0x22
+#define GSM48_MT_RR_PAG_REQ_3		0x24
+#define GSM48_MT_RR_PAG_RESP		0x27
+#define GSM48_MT_RR_NOTIF_NCH		0x20
+#define GSM48_MT_RR_NOTIF_FACCH		0x25
+#define GSM48_MT_RR_NOTIF_RESP		0x26
+
+#define GSM48_MT_RR_SYSINFO_8		0x18
+#define GSM48_MT_RR_SYSINFO_1		0x19
+#define GSM48_MT_RR_SYSINFO_2		0x1a
+#define GSM48_MT_RR_SYSINFO_3		0x1b
+#define GSM48_MT_RR_SYSINFO_4		0x1c
+#define GSM48_MT_RR_SYSINFO_5		0x1d
+#define GSM48_MT_RR_SYSINFO_6		0x1e
+#define GSM48_MT_RR_SYSINFO_7		0x1f
+
+#define GSM48_MT_RR_SYSINFO_2bis	0x02
+#define GSM48_MT_RR_SYSINFO_2ter	0x03
+#define GSM48_MT_RR_SYSINFO_5bis	0x05
+#define GSM48_MT_RR_SYSINFO_5ter	0x06
+#define GSM48_MT_RR_SYSINFO_9		0x04
+#define GSM48_MT_RR_SYSINFO_13		0x00
+
+#define GSM48_MT_RR_SYSINFO_16		0x3d
+#define GSM48_MT_RR_SYSINFO_17		0x3e
+
+#define GSM48_MT_RR_CHAN_MODE_MODIF	0x10
+#define GSM48_MT_RR_STATUS		0x12
+#define GSM48_MT_RR_CHAN_MODE_MODIF_ACK	0x17
+#define GSM48_MT_RR_FREQ_REDEF		0x14
+#define GSM48_MT_RR_MEAS_REP		0x15
+#define GSM48_MT_RR_CLSM_CHG		0x16
+#define GSM48_MT_RR_CLSM_ENQ		0x13
+#define GSM48_MT_RR_EXT_MEAS_REP	0x36
+#define GSM48_MT_RR_EXT_MEAS_REP_ORD	0x37
+#define GSM48_MT_RR_GPRS_SUSP_REQ	0x34
+
+#define GSM48_MT_RR_VGCS_UPL_GRANT	0x08
+#define GSM48_MT_RR_UPLINK_RELEASE	0x0e
+#define GSM48_MT_RR_UPLINK_FREE		0x0c
+#define GSM48_MT_RR_UPLINK_BUSY		0x2a
+#define GSM48_MT_RR_TALKER_IND		0x11
+
+#define GSM48_MT_RR_APP_INFO		0x38
+
+/* Table 10.2/3GPP TS 04.08 */
+#define GSM48_MT_MM_IMSI_DETACH_IND	0x01
+#define GSM48_MT_MM_LOC_UPD_ACCEPT	0x02
+#define GSM48_MT_MM_LOC_UPD_REJECT	0x04
+#define GSM48_MT_MM_LOC_UPD_REQUEST	0x08
+
+#define GSM48_MT_MM_AUTH_REJ		0x11
+#define GSM48_MT_MM_AUTH_REQ		0x12
+#define GSM48_MT_MM_AUTH_RESP		0x14
+#define GSM48_MT_MM_ID_REQ		0x18
+#define GSM48_MT_MM_ID_RESP		0x19
+#define GSM48_MT_MM_TMSI_REALL_CMD	0x1a
+#define GSM48_MT_MM_TMSI_REALL_COMPL	0x1b
+
+#define GSM48_MT_MM_CM_SERV_ACC		0x21
+#define GSM48_MT_MM_CM_SERV_REJ		0x22
+#define GSM48_MT_MM_CM_SERV_ABORT	0x23
+#define GSM48_MT_MM_CM_SERV_REQ		0x24
+#define GSM48_MT_MM_CM_SERV_PROMPT	0x25
+#define GSM48_MT_MM_CM_REEST_REQ	0x28
+#define GSM48_MT_MM_ABORT		0x29
+
+#define GSM48_MT_MM_NULL		0x30
+#define GSM48_MT_MM_STATUS		0x31
+#define GSM48_MT_MM_INFO		0x32
+
+/* Table 10.3/3GPP TS 04.08 */
+#define GSM48_MT_CC_ALERTING		0x01
+#define GSM48_MT_CC_CALL_CONF		0x08
+#define GSM48_MT_CC_CALL_PROC		0x02
+#define GSM48_MT_CC_CONNECT		0x07
+#define GSM48_MT_CC_CONNECT_ACK		0x0f
+#define GSM48_MT_CC_EMERG_SETUP		0x0e
+#define GSM48_MT_CC_PROGRESS		0x03
+#define GSM48_MT_CC_ESTAB		0x04
+#define GSM48_MT_CC_ESTAB_CONF		0x06
+#define GSM48_MT_CC_RECALL		0x0b
+#define GSM48_MT_CC_START_CC		0x09
+#define GSM48_MT_CC_SETUP		0x05
+
+#define GSM48_MT_CC_MODIFY		0x17
+#define GSM48_MT_CC_MODIFY_COMPL	0x1f
+#define GSM48_MT_CC_MODIFY_REJECT	0x13
+#define GSM48_MT_CC_USER_INFO		0x10
+#define GSM48_MT_CC_HOLD		0x18
+#define GSM48_MT_CC_HOLD_ACK		0x19
+#define GSM48_MT_CC_HOLD_REJ		0x1a
+#define GSM48_MT_CC_RETR		0x1c
+#define GSM48_MT_CC_RETR_ACK		0x1d
+#define GSM48_MT_CC_RETR_REJ		0x1e
+
+#define GSM48_MT_CC_DISCONNECT		0x25
+#define GSM48_MT_CC_RELEASE		0x2d
+#define GSM48_MT_CC_RELEASE_COMPL	0xea
+
+#define GSM48_MT_CC_CONG_CTRL		0x39
+#define GSM48_MT_CC_NOTIFY		0x3e
+#define GSM48_MT_CC_STATUS		0x3d
+#define GSM48_MT_CC_STATUS_ENQ		0x34
+#define GSM48_MT_CC_START_DTMF		0x35
+#define GSM48_MT_CC_STOP_DTMF		0x31
+#define GSM48_MT_CC_STOP_DTMF_ACK	0x32
+#define GSM48_MT_CC_START_DTMF_ACK	0x36
+#define GSM48_MT_CC_START_DTMF_REJ	0x37
+#define GSM48_MT_CC_FACILITY		0x3a
+
+/* FIXME: Table 10.4 / 10.4a (GPRS) */
+
+/* Section 10.5.2.26, Table 10.5.64 */
+#define GSM48_PM_MASK		0x03
+#define GSM48_PM_NORMAL		0x00
+#define GSM48_PM_EXTENDED	0x01
+#define GSM48_PM_REORG		0x02
+#define GSM48_PM_SAME		0x03
+
+/* Table 10.5.4 */
+#define GSM_MI_TYPE_MASK	0x07
+#define GSM_MI_TYPE_NONE	0x00
+#define GSM_MI_TYPE_IMSI	0x01
+#define GSM_MI_TYPE_IMEI	0x02
+#define GSM_MI_TYPE_IMEISV	0x03
+#define GSM_MI_TYPE_TMSI	0x04
+#define GSM_MI_ODD		0x08
+
+#endif
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
new file mode 100644
index 0000000..51e246c
--- /dev/null
+++ b/include/openbsc/gsm_data.h
@@ -0,0 +1,74 @@
+#ifndef _GSM_DATA_H
+#define _GSM_DATA_H
+
+#include <sys/types.h>
+
+#define GSM_MAX_BTS	8
+#define BTS_MAX_TRX	8
+
+#define HARDCODED_ARFCN 123
+
+/* communications link with a BTS */
+struct gsm_bts_link {
+	struct gsm_bts *bts;
+};
+
+#define BTS_TRX_F_ACTIVATED	0x0001
+/* One Timeslot in a TRX */
+struct gsm_bts_trx_ts {
+	struct gsm_bts_trx *trx;
+	/* number of this timeslot at the TRX */
+	u_int8_t nr;
+
+	unsigned int flags;
+};
+
+/* One TRX in a BTS */
+struct gsm_bts_trx {
+	struct gsm_bts *bts;
+	/* number of this TRX in the BTS */
+	u_int8_t nr;
+
+	u_int16_t arfcn;
+	struct gsm_bts_trx_ts ts[8];
+};
+
+/* One BTS */
+struct gsm_bts {
+	struct gsm_network *network;
+	/* number of ths BTS in network */
+	u_int8_t nr;
+	/* location area code of this BTS */
+	u_int8_t location_area_code;
+
+	/* Abis network management O&M handle */
+	struct abis_nm_h *nmh;
+	/* number of this BTS on given E1 link */
+	u_int8_t bts_nr;
+
+	/* CCCH is on C0 */
+	struct gsm_bts_trx *c0;
+	/* transceivers */
+	int num_trx;
+	struct gsm_bts_trx trx[BTS_MAX_TRX+1];
+};
+
+struct gsm_ms {
+	unsigned long imei;
+};
+
+struct gsm_network {
+	/* global parameters */
+	u_int8_t country_code;
+	u_int8_t network_code;
+
+	unsigned int num_bts;
+	/* private lists */
+	struct gsm_bts	bts[GSM_MAX_BTS+1];
+	struct gsm_ms	*ms;
+	struct gsm_subscriber *subscriber;
+};
+
+struct gsm_network *gsm_network_init(unsigned int num_bts, u_int8_t country_code,
+				     u_int8_t network_code);
+#endif
diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h
new file mode 100644
index 0000000..d5c6eff
--- /dev/null
+++ b/include/openbsc/gsm_subscriber.h
@@ -0,0 +1,16 @@
+#ifndef _GSM_SUBSCR_H
+#define _GSM_SUBSCR_H
+
+#include <sys/types.h>
+#include "gsm_data.h"
+
+struct gsm_subscriber {
+	u_int8_t *name;
+	u_int8_t tmsi[4];
+};
+
+struct gsm_subscriber *subscr_get_by_tmsi(u_int8_t *tmsi);
+struct gsm_subscriber *subscr_get_by_imsi(u_int8_t *imsi);
+int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts);
+
+#endif /* _GSM_SUBSCR_H */
diff --git a/include/openbsc/linuxlist.h b/include/openbsc/linuxlist.h
new file mode 100644
index 0000000..a89375e
--- /dev/null
+++ b/include/openbsc/linuxlist.h
@@ -0,0 +1,360 @@
+#ifndef _LINUX_LLIST_H
+#define _LINUX_LLIST_H
+
+#include <stddef.h>
+
+#ifndef inline
+#define inline __inline__
+#endif
+
+static inline void prefetch(const void *x) {;}
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+        const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+        (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized llist entries.
+ */
+#define LLIST_POISON1  ((void *) 0x00100100)
+#define LLIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked llist implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole llists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct llist_head {
+	struct llist_head *next, *prev;
+};
+
+#define LLIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LLIST_HEAD(name) \
+	struct llist_head name = LLIST_HEAD_INIT(name)
+
+#define INIT_LLIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_add(struct llist_head *new,
+			      struct llist_head *prev,
+			      struct llist_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * llist_add - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void llist_add(struct llist_head *new, struct llist_head *head)
+{
+	__llist_add(new, head, head->next);
+}
+
+/**
+ * llist_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: llist head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void llist_add_tail(struct llist_head *new, struct llist_head *head)
+{
+	__llist_add(new, head->prev, head);
+}
+
+/*
+ * Delete a llist entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal llist manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * llist_del - deletes entry from llist.
+ * @entry: the element to delete from the llist.
+ * Note: llist_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void llist_del(struct llist_head *entry)
+{
+	__llist_del(entry->prev, entry->next);
+	entry->next = LLIST_POISON1;
+	entry->prev = LLIST_POISON2;
+}
+
+/**
+ * llist_del_init - deletes entry from llist and reinitialize it.
+ * @entry: the element to delete from the llist.
+ */
+static inline void llist_del_init(struct llist_head *entry)
+{
+	__llist_del(entry->prev, entry->next);
+	INIT_LLIST_HEAD(entry); 
+}
+
+/**
+ * llist_move - delete from one llist and add as another's head
+ * @llist: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void llist_move(struct llist_head *llist, struct llist_head *head)
+{
+        __llist_del(llist->prev, llist->next);
+        llist_add(llist, head);
+}
+
+/**
+ * llist_move_tail - delete from one llist and add as another's tail
+ * @llist: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void llist_move_tail(struct llist_head *llist,
+				  struct llist_head *head)
+{
+        __llist_del(llist->prev, llist->next);
+        llist_add_tail(llist, head);
+}
+
+/**
+ * llist_empty - tests whether a llist is empty
+ * @head: the llist to test.
+ */
+static inline int llist_empty(const struct llist_head *head)
+{
+	return head->next == head;
+}
+
+static inline void __llist_splice(struct llist_head *llist,
+				 struct llist_head *head)
+{
+	struct llist_head *first = llist->next;
+	struct llist_head *last = llist->prev;
+	struct llist_head *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
+/**
+ * llist_splice - join two llists
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ */
+static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
+{
+	if (!llist_empty(llist))
+		__llist_splice(llist, head);
+}
+
+/**
+ * llist_splice_init - join two llists and reinitialise the emptied llist.
+ * @llist: the new llist to add.
+ * @head: the place to add it in the first llist.
+ *
+ * The llist at @llist is reinitialised
+ */
+static inline void llist_splice_init(struct llist_head *llist,
+				    struct llist_head *head)
+{
+	if (!llist_empty(llist)) {
+		__llist_splice(llist, head);
+		INIT_LLIST_HEAD(llist);
+	}
+}
+
+/**
+ * llist_entry - get the struct for this entry
+ * @ptr:	the &struct llist_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * llist_for_each	-	iterate over a llist
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each(pos, head) \
+	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+        	pos = pos->next, prefetch(pos->next))
+
+/**
+ * __llist_for_each	-	iterate over a llist
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ *
+ * This variant differs from llist_for_each() in that it's the
+ * simplest possible llist iteration code, no prefetching is done.
+ * Use this for code that knows the llist to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __llist_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * llist_for_each_prev	-	iterate over a llist backwards
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_prev(pos, head) \
+	for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+        	pos = pos->prev, prefetch(pos->prev))
+        	
+/**
+ * llist_for_each_safe	-	iterate over a llist safe against removal of llist entry
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @n:		another &struct llist_head to use as temporary storage
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * llist_for_each_entry	-	iterate over llist of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry(pos, head, member)				\
+	for (pos = llist_entry((head)->next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head); 					\
+	     pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_reverse - iterate backwards over llist of given type.
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_reverse(pos, head, member)			\
+	for (pos = llist_entry((head)->prev, typeof(*pos), member),	\
+		     prefetch(pos->member.prev);			\
+	     &pos->member != (head); 					\
+	     pos = llist_entry(pos->member.prev, typeof(*pos), member),	\
+		     prefetch(pos->member.prev))
+
+/**
+ * llist_for_each_entry_continue -	iterate over llist of given type
+ *			continuing after existing point
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_continue(pos, head, member) 		\
+	for (pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head);					\
+	     pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     prefetch(pos->member.next))
+
+/**
+ * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = llist_entry((head)->next, typeof(*pos), member),	\
+		n = llist_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = llist_entry(n->member.next, typeof(*n), member))
+
+/**
+ * llist_for_each_rcu	-	iterate over an rcu-protected llist
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_rcu(pos, head) \
+	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+        	pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
+        	
+#define __llist_for_each_rcu(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+        	pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
+        	
+/**
+ * llist_for_each_safe_rcu	-	iterate over an rcu-protected llist safe
+ *					against removal of llist entry
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @n:		another &struct llist_head to use as temporary storage
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_safe_rcu(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
+
+/**
+ * llist_for_each_entry_rcu	-	iterate over rcu llist of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your llist.
+ * @member:	the name of the llist_struct within the struct.
+ */
+#define llist_for_each_entry_rcu(pos, head, member)			\
+	for (pos = llist_entry((head)->next, typeof(*pos), member),	\
+		     prefetch(pos->member.next);			\
+	     &pos->member != (head); 					\
+	     pos = llist_entry(pos->member.next, typeof(*pos), member),	\
+		     ({ smp_read_barrier_depends(); 0;}),		\
+		     prefetch(pos->member.next))
+
+
+/**
+ * llist_for_each_continue_rcu	-	iterate over an rcu-protected llist 
+ *			continuing after existing point.
+ * @pos:	the &struct llist_head to use as a loop counter.
+ * @head:	the head for your llist.
+ */
+#define llist_for_each_continue_rcu(pos, head) \
+	for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
+        	(pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
+
+
+#endif
diff --git a/include/openbsc/msgb.h b/include/openbsc/msgb.h
new file mode 100644
index 0000000..b0740ed
--- /dev/null
+++ b/include/openbsc/msgb.h
@@ -0,0 +1,74 @@
+#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.
+ *
+ */
+
+struct bts_link;
+
+struct msgb {
+	/* ptr to the incoming (RX) or outgoing (TX) BTS link */
+	struct gsm_bts_link *bts_link;
+
+	u_int8_t l2_off;
+	u_int8_t l3_off;
+
+	u_int16_t data_len;
+	u_int16_t len;
+
+	unsigned char *head;
+	unsigned char *tail;
+	unsigned char *data;
+	unsigned char _data[0];
+};
+
+extern struct msgb *msgb_alloc(u_int16_t size);
+extern void msgb_free(struct msgb *m);
+
+#define msgb_l2(m)	((void *)(m->data + m->l2_off))
+#define msgb_l3(m)	((void *)(m->data + m->l3_off))
+
+static inline unsigned int msgb_headlen(const struct msgb *msgb)
+{
+	return msgb->len - msgb->data_len;
+}
+static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len)
+{
+	unsigned char *tmp = msgb->tail;
+	msgb->tail += len;
+	msgb->len += len;
+	return tmp;
+}
+static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len)
+{
+	msgb->data -= len;
+	msgb->len += len;
+	return msgb->data;
+}
+static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
+{
+	msgb->len -= len;
+	return msgb->data += len;
+}
+static inline int msgb_tailroom(const struct msgb *msgb)
+{
+	return (msgb->data + msgb->data_len) - msgb->tail;
+}
+
+#endif /* _MSGB_H */
diff --git a/include/openbsc/select.h b/include/openbsc/select.h
new file mode 100644
index 0000000..f98f72c
--- /dev/null
+++ b/include/openbsc/select.h
@@ -0,0 +1,17 @@
+#ifndef _BSC_SELECT_H
+#define _BSC_SELECT_H
+
+#define BSC_FD_READ	0x0001
+#define BSC_FD_WRITE	0x0002
+#define BSC_FD_EXCEPT	0x0004
+
+struct bsc_fd {
+	struct llist_head list;
+	int fd;
+	unsigned int when;
+	int (*cb)(struct bsc_fd *fd, unsigned int what);
+	void *data;
+	unsigned int priv_nr;
+};
+
+#endif /* _BSC_SELECT_H */
diff --git a/include/openbsc/tlv.h b/include/openbsc/tlv.h
new file mode 100644
index 0000000..4c00772
--- /dev/null
+++ b/include/openbsc/tlv.h
@@ -0,0 +1,66 @@
+#ifndef _TLV_H
+#define _TLV_H
+
+#include <sys/types.h>
+#include <string.h>
+
+#define TLV_GROSS_LEN(x)	(x+2)
+#define TLV16_GROSS_LEN(x)	((2*x)+2)
+
+static inline u_int8_t *tlv_put(u_int8_t *buf, u_int8_t tag, u_int8_t len,
+				const u_int8_t *val)
+{
+	*buf++ = tag;
+	*buf++ = len;
+	memcpy(buf, val, len);
+	return buf + len;
+}
+
+static inline u_int8_t *tlv16_put(u_int8_t *buf, u_int8_t tag, u_int8_t len,
+				const u_int16_t *val)
+{
+	*buf++ = tag;
+	*buf++ = len;
+	memcpy(buf, val, len*2);
+	return buf + len*2;
+}
+
+static inline u_int8_t *msgb_tlv16_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int16_t *val)
+{
+	u_int8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len));
+	return tlv16_put(buf, tag, len, val);
+}
+
+static inline u_int8_t *tv_put(u_int8_t *buf, u_int8_t tag, 
+				u_int8_t val)
+{
+	*buf++ = tag;
+	*buf++ = val;
+	return buf;
+}
+
+static inline u_int8_t *msgb_tlv_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val)
+{
+	u_int8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len));
+	return tlv_put(buf, tag, len, val);
+}
+
+static inline u_int8_t *msgb_tv_put(struct msgb *msg, u_int8_t tag, u_int8_t val)
+{
+	u_int8_t *buf = msgb_put(msg, 2);
+	return tv_put(buf, tag, val);
+}
+
+static inline u_int8_t *msgb_tlv_push(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val)
+{
+	u_int8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len));
+	return tlv_put(buf, tag, len, val);
+}
+
+static inline u_int8_t *msgb_tv_push(struct msgb *msg, u_int8_t tag, u_int8_t val)
+{
+	u_int8_t *buf = msgb_push(msg, 2);
+	return tv_put(buf, tag, val);
+}
+
+#endif /* _TLV_H */