* add trau_mux implementation to relay from one incoming TRAU
  channel to another one (simple voice call switching)
* add a way more generic E1 input layer, abstracting out the misdn
  low-level interface. This also adds infrastructure for multiple TRX
  in one BTS, as well as multiple BTS on one E1 link
* add a E1 subchannel multiplexer for sending multiple 16kbit sub-channels
  one one 64kBps E1 channel
* add TRAU IDLE frame generation
* terminate bsc_hack in case there is a E1 / mISDN init error
* introduce 'e1_config.c' file with static configuration of our
  E1 setup (which TRX/BTS is configured for which TEI/SAPI/E1). This should
  later become a config file rather than a compiled C file.

WARNING: all this compiles but is not tested yet.  Expect fix-up committs over
the next hours or so

diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h
index 2df941e..e75f108 100644
--- a/include/openbsc/abis_nm.h
+++ b/include/openbsc/abis_nm.h
@@ -486,5 +486,6 @@
 			  u_int8_t win_size, int forced, gsm_cbfn *cbfn);
 int abis_nm_bs11_set_ext_time(struct gsm_bts *bts);
 int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect);
+int abis_nm_bs11_restart(struct gsm_bts *bts);
 
 #endif /* _NM_H */
diff --git a/include/openbsc/e1_input.h b/include/openbsc/e1_input.h
new file mode 100644
index 0000000..29c29d0
--- /dev/null
+++ b/include/openbsc/e1_input.h
@@ -0,0 +1,137 @@
+#ifndef _E1_INPUT_H
+#define _E1_INPUT_H
+
+#include <stdlib.h>
+
+#include <openbsc/linuxlist.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/msgb.h>
+#include <openbsc/select.h>
+#include <openbsc/subchan_demux.h>
+
+#define NUM_E1_TS   32
+
+enum e1inp_sign_type {
+	E1INP_SIGN_NONE,
+	E1INP_SIGN_OML,
+	E1INP_SIGN_RSL,
+};
+
+struct e1inp_ts;
+
+struct e1inp_sign_link {
+	/* list of signalling links */
+	struct llist_head list;
+
+	/* to which timeslot do we belong? */
+	struct e1inp_ts *ts;
+
+	enum e1inp_sign_type type;
+
+	/* trx for msg->trx of received msgs */	
+	struct gsm_bts_trx *trx;
+
+	/* msgb queue of to-be-transmitted msgs */
+	struct llist_head tx_list;
+
+	/* SAPI and TEI on the E1 TS */
+	u_int8_t sapi;
+	u_int8_t tei;
+
+	union {
+		struct {
+			u_int8_t channel;
+		} misdn;
+	} driver;
+};
+
+enum e1inp_ts_type {
+	E1INP_TS_TYPE_NONE,
+	E1INP_TS_TYPE_SIGN,
+	E1INP_TS_TYPE_TRAU,
+};
+
+/* A timeslot in the E1 interface */
+struct e1inp_ts {
+	enum e1inp_ts_type type;
+	int num;
+
+	/* to which line do we belong ? */
+	struct e1inp_line *line;
+
+	union {
+		struct {
+			struct llist_head sign_links;
+		} sign;
+		struct {
+			/* subchannel demuxer for frames from E1 */
+			struct subch_demux demux;
+			/* subchannel muxer for frames to E1 */
+			struct subch_mux mux;
+		} trau;
+	};
+	union {
+		struct {
+			/* mISDN driver has one fd for each ts */
+			struct bsc_fd fd;
+		} misdn;
+	} driver;
+};
+
+struct e1inp_driver {
+	struct llist_head list;
+	const char *name;
+	int (*want_write)(struct e1inp_ts *ts);
+};	
+
+struct e1inp_line {
+	struct llist_head list;
+	unsigned int num;
+	const char *name;
+
+	/* array of timestlots */
+	struct e1inp_ts ts[NUM_E1_TS];
+
+	struct e1inp_driver *driver;
+	void *driver_data;
+};
+
+/* register a driver with the E1 core */
+int e1inp_driver_register(struct e1inp_driver *drv);
+
+/* register a line with the E1 core */
+int e1inp_line_register(struct e1inp_line *line);
+
+/* find a sign_link for given TEI and SAPI in a TS */
+struct e1inp_sign_link *
+e1inp_lookup_sign_link(struct e1inp_ts *ts, u_int8_t tei,
+			u_int8_t sapi);
+
+/* create a new signalling link in a E1 timeslot */
+struct e1inp_sign_link *
+e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type,
+			struct gsm_bts_trx *trx, u_int8_t tei,
+			u_int8_t sapi);
+
+/* configure and initialize one e1inp_ts */
+int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line,
+		    enum e1inp_ts_type type);
+
+/* Call from the Stack: configuration of this TS has changed */
+int e1inp_update_ts(struct e1inp_ts *ts);
+
+/* Receive a packet from the E1 driver */
+int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
+		u_int8_t tei, u_int8_t sapi);
+
+/* called by driver if it wants to transmit on a given TS */
+struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts,
+			 struct e1inp_sign_link **sign_link);
+
+/* called by driver in case some kind of link state event */
+int e1inp_event(struct e1inp_ts *ts, int evt, u_int8_t tei, u_int8_t sapi);
+
+/* called by TRAU muxer to obtain the destination mux entity */
+struct subch_mux *e1inp_get_mux(u_int8_t e1_nr, u_int8_t ts_nr);
+
+#endif /* _E1_INPUT_H */
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
index 75b3db5..b96ec40 100644
--- a/include/openbsc/gsm_data.h
+++ b/include/openbsc/gsm_data.h
@@ -166,6 +166,8 @@
 	struct gsm_bts *bts;
 	/* number of this TRX in the BTS */
 	u_int8_t nr;
+	/* how do we talk RSL with this TRX? */
+	struct e1inp_sign_link *rsl_link;
 
 	u_int16_t arfcn;
 	struct gsm_bts_trx_ts ts[TRX_NR_TS];
@@ -215,6 +217,8 @@
 	u_int8_t location_area_code;
 	/* type of BTS */
 	enum gsm_bts_type type;
+	/* how do we talk OML with this TRX? */
+	struct e1inp_sign_link *oml_link;
 
 	/* Abis network management O&M handle */
 	struct abis_nm_h *nmh;
@@ -255,10 +259,8 @@
 
 enum gsm_e1_event {
 	EVT_E1_NONE,
-	EVT_E1_OML_UP,
-	EVT_E1_RSL_UP,
-	EVT_E1_OML_DN,
-	EVT_E1_RSL_DN,
+	EVT_E1_TEI_UP,
+	EVT_E1_TEI_DN,
 };
 
 #endif
diff --git a/include/openbsc/subchan_demux.h b/include/openbsc/subchan_demux.h
index 373cf4a..23c9032 100644
--- a/include/openbsc/subchan_demux.h
+++ b/include/openbsc/subchan_demux.h
@@ -1,6 +1,6 @@
 #ifndef _SUBCH_DEMUX_H
 #define _SUBCH_DEMUX_H
-/* A E1 sub-channel demultiplexer with TRAU frame sync */
+/* A E1 sub-channel (de)multiplexer with TRAU frame sync */
 
 /* (C) 2009 by Harald Welte <laforge@gnumonks.org>
  * All Rights Reserved
@@ -22,26 +22,77 @@
  */
 
 #include <sys/types.h>
+#include <openbsc/linuxlist.h>
 
 #define NR_SUBCH	4
 #define TRAU_FRAME_SIZE	40
 #define TRAU_FRAME_BITS	(TRAU_FRAME_SIZE*8)
 
-struct subch {
+/***********************************************************************/
+/* DEMULTIPLEXER */
+/***********************************************************************/
+
+struct demux_subch {
 	u_int8_t out_bitbuf[TRAU_FRAME_BITS];
 	u_int8_t out_idx; /* next bit to be written in out_bitbuf */
 };
 
 struct subch_demux {
+	/* bitmask of currently active subchannels */
 	u_int8_t chan_activ;
-	struct subch subch[NR_SUBCH];
+	/* one demux_subch struct for every subchannel */
+	struct demux_subch subch[NR_SUBCH];
+	/* callback to be called once we have received a complete
+	 * frame on a given subchannel */
 	int (*out_cb)(struct subch_demux *dmx, int ch, u_int8_t *data, int len,
 		      void *);
+	/* user-provided data, transparently passed to out_cb() */
 	void *data;
 };
 
+/* initialize one demultiplexer instance */
 int subch_demux_init(struct subch_demux *dmx);
+
+/* feed 'len' number of muxed bytes into the demultiplexer */
 int subch_demux_in(struct subch_demux *dmx, u_int8_t *data, int len);
+
+/* activate decoding/processing for one subchannel */
 int subch_demux_activate(struct subch_demux *dmx, int subch);
+
+/* deactivate decoding/processing for one subchannel */
 int subch_demux_deactivate(struct subch_demux *dmx, int subch);
+
+/***********************************************************************/
+/* MULTIPLEXER */
+/***********************************************************************/
+
+/* one element in the tx_queue of a muxer sub-channel */
+struct subch_txq_entry {
+	struct llist_head list;
+
+	unsigned int bit_len;	/* total number of bits in 'bits' */
+	unsigned int next_bit;	/* next bit to be transmitted */
+
+	u_int8_t bits[0];	/* one bit per byte */
+};
+
+struct mux_subch {
+	struct llist_head tx_queue;
+};
+
+/* structure representing one instance of the subchannel muxer */
+struct subch_mux {
+	struct mux_subch subch[NR_SUBCH];
+};
+
+/* initialize a subchannel muxer instance */
+int subchan_mux_init(struct subch_mux *mx);
+
+/* request the output of 'len' multiplexed bytes */
+int subchan_mux_out(struct subch_mux *mx, u_int8_t *data, int len);
+
+/* enqueue some data into one sub-channel of the muxer */
+int subchan_mux_enqueue(struct subch_mux *mx, int s_nr, const u_int8_t *data,
+			int len);
+
 #endif /* _SUBCH_DEMUX_H */
diff --git a/include/openbsc/trau_frame.h b/include/openbsc/trau_frame.h
index 7f0a2e6..5923d4a 100644
--- a/include/openbsc/trau_frame.h
+++ b/include/openbsc/trau_frame.h
@@ -59,6 +59,7 @@
 int decode_trau_frame(struct decoded_trau_frame *fr, const u_int8_t *trau_bits);
 int encode_trau_frame(u_int8_t *trau_bits, const struct decoded_trau_frame *fr);
 int trau_frame_up2down(struct decoded_trau_frame *fr);
+u_int8_t *trau_idle_frame(void);
 
 
 #endif /* _TRAU_FRAME_H */
diff --git a/include/openbsc/trau_mux.h b/include/openbsc/trau_mux.h
new file mode 100644
index 0000000..43836db
--- /dev/null
+++ b/include/openbsc/trau_mux.h
@@ -0,0 +1,41 @@
+/* Simple TRAU frame reflector to route voice calls */
+
+/* (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.
+ *
+ */
+
+/* The "TRAU mux map" defines which particular 16kbit sub-slot (in which E1
+ * timeslot on which E1 interface) should be directly muxed to which other 
+ * sub-slot.  Entries in the mux map are always bi-directional. 
+ *
+ * The idea of all this is to directly switch voice channels in the BSC
+ * from one phone to another.  We do this right now since we don't support
+ * any external interface for voice channels, and in the future as an
+ * optimization to routing them externally.
+ */
+
+/* map a TRAU mux map entry */
+int trau_mux_map(const struct gsm_e1_subslot *src,
+		 const struct gsm_e1_subslot *dst);
+
+/* unmap a TRAU mux map entry */
+int trau_mux_unmap(const struct gsm_e1_subslot *ss);
+
+/* we get called by subchan_demux */
+int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
+		   const u_int8_t *trau_bits, int num_bits);