libgb: don't call directly into GMM / LLC layer

Instead of direct function calls to individual functions, we now
generate primitives (osmo_prim) and send them to one
application-provided function "bssgp_prim_cb()"
diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h
index 4fcdfb5..e060fc0 100644
--- a/openbsc/include/osmocom/gprs/gprs_bssgp.h
+++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h
@@ -144,6 +144,7 @@
 /* Our implementation */
 
 #include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/prim.h>
 
 /* gprs_bssgp_util.c */
 extern struct gprs_ns_inst *bssgp_nsi;
@@ -155,6 +156,40 @@
 /* Chapter 10.4.14: Status */
 int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg);
 
+enum bssgp_prim {
+	PRIM_BSSGP_DL_UD,
+	PRIM_BSSGP_UL_UD,
+	PRIM_BSSGP_PTM_UD,
+
+	PRIM_BSSGP_GMM_SUSPEND,
+	PRIM_BSSGP_GMM_RESUME,
+	PRIM_BSSGP_GMM_PAGING,
+
+	PRIM_NM_FLUSH_LL,
+	PRIM_NM_LLC_DISCARDED,
+	PRIM_NM_BVC_RESET,
+	PRIM_NM_BVC_BLOCK,
+	PRIM_NM_BVC_UNBLOCK,
+};
+
+struct osmo_bssgp_prim {
+	struct osmo_prim_hdr oph;
+
+	/* common fields */
+	uint16_t nsei;
+	uint16_t bvci;
+	uint32_t tlli;
+	struct tlv_parsed *tp;
+	struct gprs_ra_id *ra_id;
+
+	/* specific fields */
+	union {
+		struct {
+			uint8_t *suspend_ref;
+		} resume;
+	} u;
+};
+
 /* gprs_bssgp.c */
 
 #define BVC_S_BLOCKED	0x0001
@@ -264,4 +299,6 @@
 int gprs_bssgp_vty_init(void);
 void gprs_bssgp_set_log_ss(int ss);
 
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
+
 #endif /* _GPRS_BSSGP_H */
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index 87cfa61..500a1b2 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -246,6 +246,11 @@
 	return gbprox_relay2peer(msg, peer, ns_bvci);
 }
 
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+	return 0;
+}
+
 /* Receive an incoming signalling message from a BSS-side NS-VC */
 static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc,
 				  uint16_t ns_bvci)
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index c1327b6..be5fe52 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -48,7 +48,6 @@
 	dup.drx_parms = mmctx->drx_parms;
 	dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
 	dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
-	dup.pdu_lifetime = 1000; /* centi-seconds */
 	memcpy(&dup.qos_profile, qos_profile_default,
 		sizeof(qos_profile_default));
 
@@ -328,7 +327,7 @@
 	/* Identifiers passed down: (BVCI, NSEI) */
 
 	/* Send BSSGP-DL-UNITDATA.req */
-	return _bssgp_tx_dl_ud(msg, 1000, NULL);
+	return _bssgp_tx_dl_ud(msg, NULL);
 }
 
 /* Send XID response to LLE */
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index a579e7e..5558879 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -49,6 +49,7 @@
 #include <openbsc/vty.h>
 #include <openbsc/sgsn.h>
 #include <openbsc/gprs_llc.h>
+#include <openbsc/gprs_gmm.h>
 
 #include <gtp.h>
 
@@ -99,6 +100,34 @@
 	return rc;
 }
 
+/* call-back function for the BSSGP protocol */
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+	struct osmo_bssgp_prim *bp;
+	bp = container_of(oph, struct osmo_bssgp_prim, oph);
+
+	switch (oph->sap) {
+	case SAP_BSSGP_LL:
+		switch (oph->primitive) {
+		case PRIM_BSSGP_UL_UD:
+			return gprs_llc_rcvmsg(oph->msg, bp->tp);
+		}
+		break;
+	case SAP_BSSGP_GMM:
+		switch (oph->primitive) {
+		case PRIM_BSSGP_GMM_SUSPEND:
+			return gprs_gmm_rx_suspend(bp->ra_id, bp->tlli);
+		case PRIM_BSSGP_GMM_RESUME:
+			return gprs_gmm_rx_resume(bp->ra_id, bp->tlli,
+						  *bp->u.resume.suspend_ref);
+		}
+		break;
+	case SAP_BSSGP_NM:
+		break;
+	}
+	return 0;
+}
+
 static void signal_handler(int signal)
 {
 	fprintf(stdout, "signal %u received\n", signal);
diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c
index ca99dd5..4775048 100644
--- a/openbsc/src/libgb/gprs_bssgp.c
+++ b/openbsc/src/libgb/gprs_bssgp.c
@@ -233,6 +233,7 @@
 static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp,	
 			      uint16_t ns_bvci)
 {
+	struct osmo_bssgp_prim nmp;
 	struct bssgp_bvc_ctx *bctx;
 	uint16_t nsei = msgb_nsei(msg);
 	uint16_t bvci;
@@ -266,6 +267,16 @@
 			bctx->ra_id.rac, bctx->cell_id, bvci);
 	}
 
+	/* Send NM_BVC_RESET.ind to NM */
+	memset(&nmp, 0, sizeof(nmp));
+	nmp.nsei = nsei;
+	nmp.bvci = bvci;
+	nmp.tp = tp;
+	nmp.ra_id = &bctx->ra_id;
+	osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_BVC_RESET,
+			PRIM_OP_INDICATION, msg);
+	bssgp_prim_cb(&nmp.oph, NULL);
+
 	/* Acknowledge the RESET to the BTS */
 	rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
 				  nsei, bvci, ns_bvci);
@@ -274,6 +285,7 @@
 
 static int bssgp_rx_bvc_block(struct msgb *msg, struct tlv_parsed *tp)
 {
+	struct osmo_bssgp_prim nmp;
 	uint16_t bvci;
 	struct bssgp_bvc_ctx *ptp_ctx;
 
@@ -295,7 +307,14 @@
 	ptp_ctx->state |= BVC_S_BLOCKED;
 	rate_ctr_inc(&ptp_ctx->ctrg->ctr[BSSGP_CTR_BLOCKED]);
 
-	/* FIXME: Send NM_BVC_BLOCK.ind to NM */
+	/* Send NM_BVC_BLOCK.ind to NM */
+	memset(&nmp, 0, sizeof(nmp));
+	nmp.nsei = msgb_nsei(msg);
+	nmp.bvci = bvci;
+	nmp.tp = tp;
+	osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_BVC_BLOCK,
+			PRIM_OP_INDICATION, msg);
+	bssgp_prim_cb(&nmp.oph, NULL);
 
 	/* We always acknowledge the BLOCKing */
 	return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, msgb_nsei(msg),
@@ -304,6 +323,7 @@
 
 static int bssgp_rx_bvc_unblock(struct msgb *msg, struct tlv_parsed *tp)
 {
+	struct osmo_bssgp_prim nmp;
 	uint16_t bvci;
 	struct bssgp_bvc_ctx *ptp_ctx;
 
@@ -324,7 +344,14 @@
 
 	ptp_ctx->state &= ~BVC_S_BLOCKED;
 
-	/* FIXME: Send NM_BVC_UNBLOCK.ind to NM */
+	/* Send NM_BVC_UNBLOCK.ind to NM */
+	memset(&nmp, 0, sizeof(nmp));
+	nmp.nsei = msgb_nsei(msg);
+	nmp.bvci = bvci;
+	nmp.tp = tp;
+	osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_BVC_UNBLOCK,
+			PRIM_OP_INDICATION, msg);
+	bssgp_prim_cb(&nmp.oph, NULL);
 
 	/* We always acknowledge the unBLOCKing */
 	return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg),
@@ -335,6 +362,7 @@
 static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp,
 			  struct bssgp_bvc_ctx *ctx)
 {
+	struct osmo_bssgp_prim gbp;
 	struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
 
 	/* extract TLLI and parse TLV IEs */
@@ -354,12 +382,21 @@
 	msgb_llch(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
 	msgb_bcid(msg) = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_CELL_ID);
 
-	return gprs_llc_rcvmsg(msg, tp);
+	/* Send BSSGP_UL_UD.ind to NM */
+	memset(&gbp, 0, sizeof(gbp));
+	gbp.nsei = ctx->nsei;
+	gbp.bvci = ctx->bvci;
+	gbp.tlli = msgb_tlli(msg);
+	gbp.tp = tp;
+	osmo_prim_init(&gbp.oph, SAP_BSSGP_LL, PRIM_BSSGP_UL_UD,
+			PRIM_OP_INDICATION, msg);
+	return bssgp_prim_cb(&gbp.oph, NULL);
 }
 
 static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp,
 			    struct bssgp_bvc_ctx *ctx)
 {
+	struct osmo_bssgp_prim gbp;
 	struct bssgp_normal_hdr *bgph =
 			(struct bssgp_normal_hdr *) msgb_bssgph(msg);
 	struct gprs_ra_id raid;
@@ -381,7 +418,15 @@
 	gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
 
 	/* Inform GMM about the SUSPEND request */
-	rc = gprs_gmm_rx_suspend(&raid, tlli);
+	memset(&gbp, 0, sizeof(gbp));
+	gbp.nsei = msgb_nsei(msg);
+	gbp.bvci = ctx->bvci;
+	gbp.tlli = tlli;
+	gbp.ra_id = &raid;
+	osmo_prim_init(&gbp.oph, SAP_BSSGP_GMM, PRIM_BSSGP_GMM_SUSPEND,
+			PRIM_OP_REQUEST, msg);
+
+	rc = bssgp_prim_cb(&gbp.oph, NULL);
 	if (rc < 0)
 		return bssgp_tx_suspend_nack(msgb_nsei(msg), tlli, &raid, NULL);
 
@@ -393,6 +438,7 @@
 static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp,
 			   struct bssgp_bvc_ctx *ctx)
 {
+	struct osmo_bssgp_prim gbp;
 	struct bssgp_normal_hdr *bgph =
 			(struct bssgp_normal_hdr *) msgb_bssgph(msg);
 	struct gprs_ra_id raid;
@@ -416,7 +462,16 @@
 	gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));
 
 	/* Inform GMM about the RESUME request */
-	rc = gprs_gmm_rx_resume(&raid, tlli, suspend_ref);
+	memset(&gbp, 0, sizeof(gbp));
+	gbp.nsei = msgb_nsei(msg);
+	gbp.bvci = ctx->bvci;
+	gbp.tlli = tlli;
+	gbp.ra_id = &raid;
+	gbp.u.resume.suspend_ref = suspend_ref;
+	osmo_prim_init(&gbp.oph, SAP_BSSGP_GMM, PRIM_BSSGP_GMM_RESUME,
+			PRIM_OP_REQUEST, msg);
+
+	rc = bssgp_prim_cb(&gbp.oph, NULL);
 	if (rc < 0)
 		return bssgp_tx_resume_nack(msgb_nsei(msg), tlli, &raid,
 					    NULL);
@@ -429,6 +484,7 @@
 static int bssgp_rx_llc_disc(struct msgb *msg, struct tlv_parsed *tp,
 			     struct bssgp_bvc_ctx *ctx)
 {
+	struct osmo_bssgp_prim nmp;
 	uint32_t tlli = 0;
 
 	if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) ||
@@ -447,8 +503,16 @@
 
 	rate_ctr_inc(&ctx->ctrg->ctr[BSSGP_CTR_DISCARDED]);
 
-	/* FIXME: send NM_LLC_DISCARDED to NM */
-	return 0;
+	/* send NM_LLC_DISCARDED to NM */
+	memset(&nmp, 0, sizeof(nmp));
+	nmp.nsei = msgb_nsei(msg);
+	nmp.bvci = ctx->bvci;
+	nmp.tlli = tlli;
+	nmp.tp = tp;
+	osmo_prim_init(&nmp.oph, SAP_BSSGP_NM, PRIM_NM_LLC_DISCARDED,
+			PRIM_OP_INDICATION, msg);
+
+	return bssgp_prim_cb(&nmp.oph, NULL);
 }
 
 static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp,