diff mbox

[6/6] gprs: Store gbproxy patching state per peer

Message ID 1404386897-27883-6-git-send-email-jerlbeck@sysmocom.de
State Superseded
Headers show

Commit Message

Jacob Erlbeck July 3, 2014, 11:28 a.m. UTC
Currently, all patching state is stored globally in the gbproxy. Thus
the feature cannot be used safely with a concentrating gbproxy (NAT).

This patch moves the state and relevant counters to the gbprox_peer
structure. It adds code to resolve the corresponding peer when
packets are received by looking at BVCI, NSEI, and BSSGP IEs (BVCI,
RAI/LAI/LAC) when the peer is not passed to the
gbprox_patch_bssgp_message() function.

Test cases are also added for the SGSN->BSS case including test cases
with invalid identifiers.

Note that this patch should make it possible to use RAI patching at a
NAT gbproxy as long as the messages are not encrypted.

Ticket: OW#1185
Sponsored-by: On-Waves ehf
---
 openbsc/src/gprs/gb_proxy.c           | 191 +++++++++++++++++++++++-----------
 openbsc/tests/gbproxy/gbproxy_test.ok |  20 ++--
 2 files changed, 139 insertions(+), 72 deletions(-)
diff mbox

Patch

diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index ea590b3..bead954 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -59,11 +59,7 @@  enum gbprox_global_ctr {
 	GBPROX_GLOB_CTR_RESTART_RESET_SGSN,
 	GBPROX_GLOB_CTR_TX_ERR_SGSN,
 	GBPROX_GLOB_CTR_OTHER_ERR,
-	GBPROX_GLOB_CTR_RAID_PATCHED_BSS,
-	GBPROX_GLOB_CTR_RAID_PATCHED_SGSN,
-	GBPROX_GLOB_CTR_APN_PATCHED,
-	GBPROX_GLOB_CTR_PATCH_CRYPT_ERR,
-	GBPROX_GLOB_CTR_PATCH_ERR,
+	GBPROX_GLOB_CTR_PATCH_PEER_ERR,
 };
 
 static const struct rate_ctr_desc global_ctr_description[] = {
@@ -78,11 +74,7 @@  static const struct rate_ctr_desc global_ctr_description[] = {
 	{ "restart.sgsn",   "Restarted RESET procedure (SGSN)" },
 	{ "tx-err.sgsn",    "NS Transmission error     (SGSN)" },
 	{ "error",          "Other error                     " },
-	{ "raid-mod.bss",   "RAID patched              (BSS )" },
-	{ "raid-mod.sgsn",  "RAID patched              (SGSN)" },
-	{ "apn-mod.sgsn",   "APN patched                     " },
-	{ "mod-crypt-err",  "Patch error: encrypted          " },
-	{ "mod-err",        "Patch error: other              " },
+	{ "mod-peer-err",   "Patch error: no peer            " },
 };
 
 static const struct rate_ctr_group_desc global_ctrg_desc = {
@@ -109,14 +101,24 @@  enum gbprox_peer_ctr {
 	GBPROX_PEER_CTR_DROPPED,
 	GBPROX_PEER_CTR_INV_NSEI,
 	GBPROX_PEER_CTR_TX_ERR,
+	GBPROX_PEER_CTR_RAID_PATCHED_BSS,
+	GBPROX_PEER_CTR_RAID_PATCHED_SGSN,
+	GBPROX_PEER_CTR_APN_PATCHED,
+	GBPROX_PEER_CTR_PATCH_CRYPT_ERR,
+	GBPROX_PEER_CTR_PATCH_ERR,
 };
 
 static const struct rate_ctr_desc peer_ctr_description[] = {
-	{ "blocked",	  "BVC Block                       " },
-	{ "unblocked",	  "BVC Unblock                     " },
-	{ "dropped",	  "BVC blocked, dropped packet     " },
-	{ "inv-nsei",	  "NSEI mismatch                   " },
-	{ "tx-err",       "NS Transmission error           " },
+	{ "blocked",	   "BVC Block                       " },
+	{ "unblocked",	   "BVC Unblock                     " },
+	{ "dropped",	   "BVC blocked, dropped packet     " },
+	{ "inv-nsei",	   "NSEI mismatch                   " },
+	{ "tx-err",	   "NS Transmission error           " },
+	{ "raid-mod.bss",  "RAID patched              (BSS )" },
+	{ "raid-mod.sgsn", "RAID patched              (SGSN)" },
+	{ "apn-mod.sgsn",  "APN patched                     " },
+	{ "mod-crypt-err", "Patch error: encrypted          " },
+	{ "mod-err",	   "Patch error: other              " },
 };
 
 static const struct rate_ctr_group_desc peer_ctrg_desc = {
@@ -126,10 +128,10 @@  static const struct rate_ctr_group_desc peer_ctrg_desc = {
 	.ctr_desc = peer_ctr_description,
 };
 
-static struct gbprox_patch_state {
+struct gbprox_patch_state {
 	int local_mnc;
 	int local_mcc;
-} gbprox_patch_state = {0};
+};
 
 struct gbprox_peer {
 	struct llist_head list;
@@ -146,6 +148,8 @@  struct gbprox_peer {
 
 	/* Counter */
 	struct rate_ctr_group *ctrg;
+
+	struct gbprox_patch_state patch_state;
 };
 
 /* Linked list of all Gb peers (except SGSN) */
@@ -195,6 +199,18 @@  static struct gbprox_peer *peer_by_lai(const uint8_t *la)
 	return NULL;
 }
 
+/* look-up a peer by its Location Area Code (LAC) */
+static struct gbprox_peer *peer_by_lac(const uint8_t *la)
+{
+	struct gbprox_peer *peer;
+	llist_for_each_entry(peer, &gbprox_bts_peers, list) {
+		if (!memcmp(peer->ra + 3, la + 3, 2))
+			return peer;
+	}
+	return NULL;
+}
+
+
 static int check_peer_nsei(struct gbprox_peer *peer, uint16_t nsei)
 {
 	if (peer->nsei != nsei) {
@@ -363,9 +379,10 @@  int gbprox_str_to_apn(uint8_t *apn_enc, const char *str, size_t max_chars)
 }
 
 /* patch RA identifier in place, update peer accordingly */
-static void gbprox_patch_raid(uint8_t *raid_enc, struct gbprox_patch_state *state,
+static void gbprox_patch_raid(uint8_t *raid_enc, struct gbprox_peer *peer,
 			      int to_bss, const char *log_text)
 {
+	struct gbprox_patch_state *state = &peer->patch_state;
 	int old_local_mcc = state->local_mcc;
 	int old_local_mnc = state->local_mnc;
 	int old_mcc;
@@ -415,10 +432,10 @@  static void gbprox_patch_raid(uint8_t *raid_enc, struct gbprox_patch_state *stat
 		     to_bss ? "BSS" : "SGSN");
 
 	if (state->local_mcc || state->local_mnc) {
-		enum gbprox_global_ctr counter =
+		enum gbprox_peer_ctr counter =
 			to_bss ?
-			GBPROX_GLOB_CTR_RAID_PATCHED_SGSN :
-			GBPROX_GLOB_CTR_RAID_PATCHED_BSS;
+			GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
+			GBPROX_PEER_CTR_RAID_PATCHED_BSS;
 
 		LOGP(DGPRS, LOGL_DEBUG,
 		       "Patching %s to %s: "
@@ -429,12 +446,13 @@  static void gbprox_patch_raid(uint8_t *raid_enc, struct gbprox_patch_state *stat
 		       raid.mcc, raid.mnc, raid.lac, raid.rac);
 
 		gsm48_construct_ra(raid_enc, &raid);
-		rate_ctr_inc(&get_global_ctrg()->ctr[counter]);
+		rate_ctr_inc(&peer->ctrg->ctr[counter]);
 	}
 }
 
 static void gbprox_patch_apn_ie(struct msgb *msg,
 				uint8_t *apn_ie, size_t apn_ie_len,
+				struct gbprox_peer *peer,
 				size_t *new_apn_ie_len, const char *log_text)
 {
 	struct apn_ie_hdr {
@@ -480,12 +498,12 @@  static void gbprox_patch_apn_ie(struct msgb *msg,
 		hdr->apn_len = gbcfg.core_apn_size;
 	}
 
-	rate_ctr_inc(&get_global_ctrg()->ctr[GBPROX_GLOB_CTR_APN_PATCHED]);
+	rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
 }
 
 static int gbprox_patch_gmm_attach_req(struct msgb *msg,
 				       uint8_t *data, size_t data_len,
-				       struct gbprox_patch_state *state,
+				       struct gbprox_peer *peer,
 				       int to_bss, int *len_change)
 {
 	/* Check minimum length, always includes the RAI */
@@ -512,14 +530,14 @@  static int gbprox_patch_gmm_attach_req(struct msgb *msg,
 	data_len -= data[0] + 1;
 	data += data[0] + 1;
 
-	gbprox_patch_raid(data, state, to_bss, "LLC/ATTACH_REQ");
+	gbprox_patch_raid(data, peer, to_bss, "LLC/ATTACH_REQ");
 
 	return 1;
 }
 
 static int gbprox_patch_gmm_attach_ack(struct msgb *msg,
 				       uint8_t *data, size_t data_len,
-				       struct gbprox_patch_state *state,
+				       struct gbprox_peer *peer,
 				       int to_bss, int *len_change)
 {
 	/* Check minimum length, always includes the RAI */
@@ -534,14 +552,14 @@  static int gbprox_patch_gmm_attach_ack(struct msgb *msg,
 	data_len -= 3;
 	data += 3;
 
-	gbprox_patch_raid(data, state, to_bss, "LLC/ATTACH_ACK");
+	gbprox_patch_raid(data, peer, to_bss, "LLC/ATTACH_ACK");
 
 	return 1;
 }
 
 static int gbprox_patch_gmm_ra_upd_req(struct msgb *msg,
 				       uint8_t *data, size_t data_len,
-				       struct gbprox_patch_state *state,
+				       struct gbprox_peer *peer,
 				       int to_bss, int *len_change)
 {
 	/* Check minimum length, always includes the RAI */
@@ -553,14 +571,14 @@  static int gbprox_patch_gmm_ra_upd_req(struct msgb *msg,
 	data_len -= 1;
 	data += 1;
 
-	gbprox_patch_raid(data, state, to_bss, "LLC/RA_UPD_REQ");
+	gbprox_patch_raid(data, peer, to_bss, "LLC/RA_UPD_REQ");
 
 	return 1;
 }
 
 static int gbprox_patch_gmm_ra_upd_ack(struct msgb *msg,
 				       uint8_t *data, size_t data_len,
-				       struct gbprox_patch_state *state,
+				       struct gbprox_peer *peer,
 				       int to_bss, int *len_change)
 {
 	/* Check minimum length, always includes the RAI */
@@ -573,14 +591,14 @@  static int gbprox_patch_gmm_ra_upd_ack(struct msgb *msg,
 	data_len -= 2;
 	data += 2;
 
-	gbprox_patch_raid(data, state, to_bss, "LLC/RA_UPD_ACK");
+	gbprox_patch_raid(data, peer, to_bss, "LLC/RA_UPD_ACK");
 
 	return 1;
 }
 
 static int gbprox_patch_gmm_ptmsi_reall_cmd(struct msgb *msg,
 					    uint8_t *data, size_t data_len,
-					    struct gbprox_patch_state *state,
+					    struct gbprox_peer *peer,
 					    int to_bss, int *len_change)
 {
 	/* Check minimum length, always includes the RAI */
@@ -594,14 +612,14 @@  static int gbprox_patch_gmm_ptmsi_reall_cmd(struct msgb *msg,
 	data_len -= 6;
 	data += 6;
 
-	gbprox_patch_raid(data, state, to_bss, "LLC/PTMSI_REALL_CMD");
+	gbprox_patch_raid(data, peer, to_bss, "LLC/PTMSI_REALL_CMD");
 
 	return 1;
 }
 
 static int gbprox_patch_gsm_act_pdp_req(struct msgb *msg,
 					uint8_t *data, size_t data_len,
-					struct gbprox_patch_state *state,
+					struct gbprox_peer *peer,
 					int to_bss, int *len_change)
 {
 	size_t new_len, old_len;
@@ -644,7 +662,7 @@  static int gbprox_patch_gsm_act_pdp_req(struct msgb *msg,
 
 	old_len = data[1] + 2;
 
-	gbprox_patch_apn_ie(msg, data, old_len, &new_len, "LLC/ACT_PDP_REQ");
+	gbprox_patch_apn_ie(msg, data, old_len, peer, &new_len, "LLC/ACT_PDP_REQ");
 
 	*len_change += (int)new_len - (int)old_len;
 	data_len -= old_len;
@@ -653,8 +671,31 @@  static int gbprox_patch_gsm_act_pdp_req(struct msgb *msg,
 	return 1;
 }
 
+struct gbprox_peer *peer_by_bssgp_tlv(struct tlv_parsed *tp)
+{
+	if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
+		uint16_t bvci;
+
+		bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
+		if (bvci >= 2)
+			return peer_by_bvci(bvci);
+	}
+
+	if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
+		uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
+		return peer_by_lac(rai);
+	}
+
+	if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
+		uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA);
+		return peer_by_lac(lai);
+	}
+
+	return NULL;
+}
+
 static int gbprox_patch_dtap(struct msgb *msg, uint8_t *data, size_t data_len,
-			     struct gbprox_patch_state *state,
+			     struct gbprox_peer *peer,
 			     enum gbproxy_patch_mode patch_mode, int to_bss,
 			     int *len_change)
 {
@@ -677,31 +718,31 @@  static int gbprox_patch_dtap(struct msgb *msg, uint8_t *data, size_t data_len,
 	switch (g48h->msg_type) {
 	case GSM48_MT_GMM_ATTACH_REQ:
 		return gbprox_patch_gmm_attach_req(msg, data, data_len,
-						   state, to_bss, len_change);
+						   peer, to_bss, len_change);
 
 	case GSM48_MT_GMM_ATTACH_ACK:
 		if (patch_mode < GBPROX_PATCH_LLC_ATTACH)
 			break;
 		return gbprox_patch_gmm_attach_ack(msg, data, data_len,
-						   state, to_bss, len_change);
+						   peer, to_bss, len_change);
 
 	case GSM48_MT_GMM_RA_UPD_REQ:
 		if (patch_mode < GBPROX_PATCH_LLC_GMM)
 			break;
 		return gbprox_patch_gmm_ra_upd_req(msg, data, data_len,
-						   state, to_bss, len_change);
+						   peer, to_bss, len_change);
 
 	case GSM48_MT_GMM_RA_UPD_ACK:
 		if (patch_mode < GBPROX_PATCH_LLC_GMM)
 			break;
 		return gbprox_patch_gmm_ra_upd_ack(msg, data, data_len,
-						   state, to_bss, len_change);
+						   peer, to_bss, len_change);
 
 	case GSM48_MT_GMM_PTMSI_REALL_CMD:
 		if (patch_mode < GBPROX_PATCH_LLC_GMM)
 			break;
 		return gbprox_patch_gmm_ptmsi_reall_cmd(msg, data, data_len,
-							state, to_bss, len_change);
+							peer, to_bss, len_change);
 
 	case GSM48_MT_GSM_ACT_PDP_REQ:
 		if (patch_mode < GBPROX_PATCH_LLC_GSM)
@@ -709,7 +750,7 @@  static int gbprox_patch_dtap(struct msgb *msg, uint8_t *data, size_t data_len,
 		if (gbcfg.core_apn == NULL)
 			break;
 		return gbprox_patch_gsm_act_pdp_req(msg, data, data_len,
-						    state, to_bss, len_change);
+						    peer, to_bss, len_change);
 	default:
 		break;
 	};
@@ -718,7 +759,7 @@  static int gbprox_patch_dtap(struct msgb *msg, uint8_t *data, size_t data_len,
 }
 
 static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
-			     struct gbprox_patch_state *state,
+			     struct gbprox_peer *peer,
 			     enum gbproxy_patch_mode patch_mode, int to_bss)
 {
 	struct gprs_llc_hdr_parsed ghp = {0};
@@ -755,7 +796,7 @@  static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
 		if (gbcfg.patch_mode > GBPROX_PATCH_LLC_ATTACH_REQ) {
 			/* LLC patch (GMM) has been requested explicitely */
 			err_info = "GMM message is encrypted";
-			err_ctr = GBPROX_GLOB_CTR_PATCH_CRYPT_ERR;
+			err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR;
 			goto patch_error;
 		}
 
@@ -766,7 +807,7 @@  static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
 	data = ghp.data;
 	data_len = ghp.data_len;
 
-	rc = gbprox_patch_dtap(msg, data, data_len, state, patch_mode, to_bss,
+	rc = gbprox_patch_dtap(msg, data, data_len, peer, patch_mode, to_bss,
 			       &len_change);
 
 	if (rc > 0) {
@@ -778,7 +819,7 @@  static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
 			/* most probably a one byte length */
 			if (llc_len > 127) {
 				err_info = "Cannot increase size";
-				err_ctr = GBPROX_GLOB_CTR_PATCH_ERR;
+				err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
 				goto patch_error;
 			}
 			llc[-1] = llc_len | 0x80;
@@ -801,7 +842,7 @@  static void gbprox_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
 
 patch_error:
 	OSMO_ASSERT(err_ctr >= 0);
-	rate_ctr_inc(&get_global_ctrg()->ctr[err_ctr]);
+	rate_ctr_inc(&peer->ctrg->ctr[err_ctr]);
 	LOGP(DGPRS, LOGL_ERROR,
 	     "Failed to patch BSSGP/GMM message as requested: %s.\n", err_info);
 
@@ -809,13 +850,14 @@  patch_error:
 }
 
 /* patch BSSGP message to use core_mcc/mnc on the SGSN side */
-static void gbprox_patch_bssgp_message(struct msgb *msg, int to_bss)
+static void gbprox_patch_bssgp_message(struct msgb *msg,
+				       struct gbprox_peer *peer, int to_bss)
 {
 	struct bssgp_normal_hdr *bgph;
 	struct bssgp_ud_hdr *budh;
 	struct tlv_parsed tp;
 	uint8_t pdu_type;
-	struct gbprox_patch_state *state = &gbprox_patch_state;
+	struct gbprox_patch_state *state = NULL;
 	uint8_t *data;
 	size_t data_len;
 	enum gbproxy_patch_mode patch_mode;
@@ -830,9 +872,6 @@  static void gbprox_patch_bssgp_message(struct msgb *msg, int to_bss)
 	if (patch_mode == GBPROX_PATCH_DEFAULT)
 		patch_mode = GBPROX_PATCH_LLC;
 
-	if (to_bss && !state->local_mcc && !state->local_mnc)
-		return;
-
 	if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
 	    pdu_type == BSSGP_PDUT_DL_UNITDATA) {
 		data = budh->data;
@@ -845,32 +884,60 @@  static void gbprox_patch_bssgp_message(struct msgb *msg, int to_bss)
 	/* fix BSSGP */
 	bssgp_tlv_parse(&tp, data, data_len);
 
-	if (TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
+	if (!peer && msgb_bvci(msg) >= 2)
+		peer = peer_by_bvci(msgb_bvci(msg));
+
+	if (!peer && !to_bss)
+		peer = peer_by_nsei(msgb_nsei(msg));
+
+	if (!peer)
+		peer = peer_by_bssgp_tlv(&tp);
+
+	if (!peer) {
+		LOGP(DLLC, LOGL_INFO,
+		     "NSEI=%d(%s) patching: didn't find peer for message, "
+		     "PDU %d\n",
+		     msgb_nsei(msg), to_bss ? "SGSN" : "BSS", pdu_type);
+		/* Increment counter */
+		rate_ctr_inc(&get_global_ctrg()->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
+		return;
+	}
+
+	state = &peer->patch_state;
+
+	if (to_bss && !state->local_mcc && !state->local_mnc)
+		return;
+
+	if (TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) {
 		gbprox_patch_raid((uint8_t *)TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
-				  state, to_bss, "ROUTING_AREA");
+				  peer, to_bss, "ROUTING_AREA");
+	}
 
 	if (TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID))
 		gbprox_patch_raid((uint8_t *)TLVP_VAL(&tp, BSSGP_IE_CELL_ID),
-				  state, to_bss, "CELL_ID");
+				  peer, to_bss, "CELL_ID");
 
 	if (TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU) &&
 	    patch_mode >= GBPROX_PATCH_LLC_ATTACH_REQ) {
 		uint8_t *llc = (uint8_t *)TLVP_VAL(&tp, BSSGP_IE_LLC_PDU);
 		size_t llc_len = TLVP_LEN(&tp, BSSGP_IE_LLC_PDU);
-		gbprox_patch_llc(msg, llc, llc_len, state, patch_mode, to_bss);
+		gbprox_patch_llc(msg, llc, llc_len, peer, patch_mode, to_bss);
 		/* Note that the tp struct might contain invalid pointers here
 		 * if the LLC field has changed its size */
 	}
 }
 
 /* feed a message down the NS-VC associated with the specified peer */
-static int gbprox_relay2sgsn(struct msgb *old_msg, uint16_t ns_bvci)
+static int gbprox_relay2sgsn(struct msgb *old_msg,
+			     struct gbprox_peer *peer, uint16_t ns_bvci)
 {
 	/* create a copy of the message so the old one can
 	 * be free()d safely when we return from gbprox_rcvmsg() */
 	struct msgb *msg = msgb_copy(old_msg, "msgb_relay2sgsn");
 	int rc;
 
+	gbprox_patch_bssgp_message(msg, peer, 0);
+
 	DEBUGP(DGPRS, "NSEI=%u proxying BTS->SGSN (NS_BVCI=%u, NSEI=%u)\n",
 		msgb_nsei(msg), ns_bvci, gbcfg.nsip_sgsn_nsei);
 
@@ -879,8 +946,6 @@  static int gbprox_relay2sgsn(struct msgb *old_msg, uint16_t ns_bvci)
 
 	strip_ns_hdr(msg);
 
-	gbprox_patch_bssgp_message(msg, 0);
-
 	rc = gprs_ns_sendmsg(bssgp_nsi, msg);
 	if (rc < 0)
 		rate_ctr_inc(&get_global_ctrg()->ctr[GBPROX_GLOB_CTR_TX_ERR_SGSN]);
@@ -971,7 +1036,7 @@  static int gbprox_rx_sig_from_bss(struct msgb *msg, uint16_t nsei,
 	struct tlv_parsed tp;
 	uint8_t pdu_type = bgph->pdu_type;
 	int data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
-	struct gbprox_peer *from_peer;
+	struct gbprox_peer *from_peer = NULL;
 	struct gprs_ra_id raid;
 
 	if (ns_bvci != 0 && ns_bvci != 1) {
@@ -1062,7 +1127,7 @@  static int gbprox_rx_sig_from_bss(struct msgb *msg, uint16_t nsei,
 
 	/* Normally, we can simply pass on all signalling messages from BSS to
 	 * SGSN */
-	return gbprox_relay2sgsn(msg, ns_bvci);
+	return gbprox_relay2sgsn(msg, from_peer, ns_bvci);
 err_no_peer:
 	LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) cannot find peer based on NSEI\n",
 		nsei);
@@ -1285,7 +1350,7 @@  int gbprox_rcvmsg(struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t ns
 	int remote_end_is_sgsn = nsei == gbcfg.nsip_sgsn_nsei;
 
 	if (remote_end_is_sgsn)
-		gbprox_patch_bssgp_message(msg, 1);
+		gbprox_patch_bssgp_message(msg, NULL, 1);
 
 	/* Only BVCI=0 messages need special treatment */
 	if (ns_bvci == 0 || ns_bvci == 1) {
@@ -1300,7 +1365,7 @@  int gbprox_rcvmsg(struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t ns
 		if (!remote_end_is_sgsn) {
 			if (peer)
 				check_peer_nsei(peer, nsei);
-			return gbprox_relay2sgsn(msg, ns_bvci);
+			return gbprox_relay2sgsn(msg, peer, ns_bvci);
 		}
 
 		/* else: SGSN -> BSS direction */
diff --git a/openbsc/tests/gbproxy/gbproxy_test.ok b/openbsc/tests/gbproxy/gbproxy_test.ok
index e038afc..40b5376 100644
--- a/openbsc/tests/gbproxy/gbproxy_test.ok
+++ b/openbsc/tests/gbproxy/gbproxy_test.ok
@@ -1621,6 +1621,7 @@  Current NS-VCIs:
 
 Peers:
   NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+    RAID patched              (BSS ): 1
 PROCESSING BVC_RESET_ACK from 0x05060708:32000
 00 00 00 00 23 04 82 10 02 
 
@@ -1664,10 +1665,10 @@  MESSAGE to BSS at 0x01020304:1111, msg length 22
 result (BVC_SUSPEND_ACK) = 22
 
 Gbproxy global:
-    RAID patched              (BSS ): 2
-    RAID patched              (SGSN): 1
 Peers:
   NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+    RAID patched              (BSS ): 2
+    RAID patched              (SGSN): 1
 --- Send message from BSS 1 to SGSN, BVCI 0x1002 ---
 
 PROCESSING UNITDATA from 0x01020304:1111
@@ -1755,11 +1756,11 @@  MESSAGE to SGSN at 0x05060708:32000, msg length 75
 result (UNITDATA) = 75
 
 Gbproxy global:
+Peers:
+  NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
     RAID patched              (BSS ): 8
     RAID patched              (SGSN): 3
     APN patched                     : 2
-Peers:
-  NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
 --- Bad cases ---
 
 PROCESSING BVC_RESET_ACK from 0x05060708:32000
@@ -1777,20 +1778,21 @@  CALLBACK, event 0, msg length 18, bvci 0x0000
 0c 1f 84 cc d1 75 8b 1b 86 00 f1 99 00 63 60 1d 81 01 
 
 NS UNITDATA MESSAGE to SGSN, BVCI 0x0000, msg length 24
-41 07 81 05 15 92 0c 1f 84 cc d1 75 8b 1b 86 11 22 33 00 63 60 1d 81 01 
+41 07 81 05 15 92 0c 1f 84 cc d1 75 8b 1b 86 00 f1 99 00 63 60 1d 81 01 
 
 MESSAGE to SGSN at 0x05060708:32000, msg length 28
-00 00 00 00 41 07 81 05 15 92 0c 1f 84 cc d1 75 8b 1b 86 11 22 33 00 63 60 1d 81 01 
+00 00 00 00 41 07 81 05 15 92 0c 1f 84 cc d1 75 8b 1b 86 00 f1 99 00 63 60 1d 81 01 
 
 result (BVC_SUSPEND_ACK) = 28
 
 Gbproxy global:
     Invalid BVC Identifier          : 1
     Invalid Routing Area Identifier : 1
-    RAID patched              (BSS ): 8
-    RAID patched              (SGSN): 4
-    APN patched                     : 2
+    Patch error: no peer            : 2
 Peers:
   NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
+    RAID patched              (BSS ): 8
+    RAID patched              (SGSN): 3
+    APN patched                     : 2
 ===== GbProxy test END