GPRS: Introduce a GPRS Gb Proxy

The ida of the Gb proxy is to aggregate Gb links with a number of BSS
and then present all the BSSGP-VC's together inside one NS-VC to the
actual SGSN.

The code is not yet expected to be complete.
diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h
index f85ac48..3040e6a 100644
--- a/openbsc/include/openbsc/gprs_bssgp.h
+++ b/openbsc/include/openbsc/gprs_bssgp.h
@@ -133,6 +133,16 @@
 	BSSGP_CAUSE_PDU_INCOMP_FEAT	= 0x28,
 };
 
+/* Our implementation */
+
+#include <osmocore/tlv.h>
+
 extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci);
 
+/* Wrapper around TLV parser to parse BSSGP IEs */
+static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len)
+{
+	return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
+}
+
 #endif /* _GPRS_BSSGP_H */
diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h
index 34a3e58..dd10d33 100644
--- a/openbsc/include/openbsc/gprs_ns.h
+++ b/openbsc/include/openbsc/gprs_ns.h
@@ -73,7 +73,37 @@
 	NS_CAUSE_UNKN_IP_TEST_FAILED	= 0x14,
 };
 
-struct gprs_nsvc;
+
+/* Our Implementation */
+#include <netinet/in.h>
+
+#define NSE_S_BLOCKED	0x0001
+#define NSE_S_ALIVE	0x0002
+
+struct gprs_nsvc {
+	struct llist_head list;
+	struct gprs_ns_inst *nsi;
+
+	u_int16_t nsei;		/* end-to-end significance */
+	u_int16_t nsvci;	/* uniquely identifies NS-VC at SGSN */
+
+	u_int32_t state;
+	u_int32_t remote_state;
+
+	struct timer_list alive_timer;
+	int timer_is_tns_alive;
+	int alive_retries;
+
+	int remote_end_is_sgsn;
+
+	union {
+		struct {
+			struct sockaddr_in bts_addr;
+		} ip;
+	};
+};
+
+
 struct gprs_ns_inst;
 
 enum gprs_ns_evt {
@@ -101,4 +131,11 @@
 /* main function for higher layers (BSSGP) to send NS messages */
 int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg);
 
+
+/* Listen for incoming GPRS packets */
+int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port);
+
+/* Establish a connection (from the BSS) to the SGSN */
+struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi,
+				struct sockaddr_in *dest, uint16_t nsvci);
 #endif
diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c
index 650d7d4..a2181b1 100644
--- a/openbsc/src/gprs_bssgp.c
+++ b/openbsc/src/gprs_bssgp.c
@@ -74,11 +74,6 @@
 	return "undefined";
 }
 
-static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len)
-{
-	return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
-}
-
 static inline struct msgb *bssgp_msgb_alloc(void)
 {
 	return msgb_alloc_headroom(4096, 128, "BSSGP");
@@ -120,7 +115,7 @@
 }
 
 /* Chapter 10.4.14: Status */
-static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg)
+int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg)
 {
 	struct msgb *msg = bssgp_msgb_alloc();
 	struct bssgp_normal_hdr *bgph =
diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c
index 6c495b0..3bb0bf9 100644
--- a/openbsc/src/gprs_ns.c
+++ b/openbsc/src/gprs_ns.c
@@ -72,30 +72,6 @@
 	},
 };
 
-#define NSE_S_BLOCKED	0x0001
-#define NSE_S_ALIVE	0x0002
-
-struct gprs_nsvc {
-	struct llist_head list;
-	struct gprs_ns_inst *nsi;
-
-	u_int16_t nsei;		/* end-to-end significance */
-	u_int16_t nsvci;	/* uniquely identifies NS-VC at SGSN */
-
-	u_int32_t state;
-	u_int32_t remote_state;
-
-	struct timer_list alive_timer;
-	int timer_is_tns_alive;
-	int alive_retries;
-
-	union {
-		struct {
-			struct sockaddr_in bts_addr;
-		} ip;
-	};
-};
-
 enum gprs_ns_ll {
 	GPRS_NS_LL_UDP,
 	GPRS_NS_LL_E1,
@@ -474,7 +450,7 @@
 	nsi->cb = cb;
 	INIT_LLIST_HEAD(&nsi->gprs_nsvcs);
 
-	return NULL;
+	return nsi;
 }
 
 void gprs_ns_destroy(struct gprs_ns_inst *nsi)
@@ -586,3 +562,24 @@
 
 	return ret;
 }
+
+/* Establish a connection (from the BSS) to the SGSN */
+struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi,
+				struct sockaddr_in *dest, uint16_t nsvci)
+{
+	struct gprs_nsvc *nsvc;
+
+	nsvc = nsvc_by_rem_addr(nsi, dest);
+	if (!nsvc) {
+		nsvc = nsvc_create(nsi, nsvci);
+		nsvc->ip.bts_addr = *dest;
+	}
+	nsvc->remote_end_is_sgsn = 1;
+
+	/* Initiate a RESET procedure */
+	if (gprs_ns_tx_simple(nsvc, NS_PDUT_RESET) < 0)
+		return NULL;
+	/* FIXME: should we run a timer and re-transmit the reset request? */
+
+	return nsvc;
+}