GTPv2_Emulation: Improve routing messages to client

Before this patch, for instance, registering an IMSI would not
necessarily mean the messaged ended up in the client registering it, due
to how the code paths were being handled.

Ideally the code should create a CLIENT candidate list based on all
registered matches, and then remove duplicates and finally send message
to each CLIENT in the resulting list. That's really not needed as of now
though.

Change-Id: If253a2b8991f0caf685058238df9a7c997983e27
diff --git a/library/GTPv2_Emulation.ttcn b/library/GTPv2_Emulation.ttcn
index 0b2cb4f..eb2b977 100644
--- a/library/GTPv2_Emulation.ttcn
+++ b/library/GTPv2_Emulation.ttcn
@@ -107,6 +107,16 @@
 	GTP2_ConnHdlr vc_conn
 };
 
+private function f_teid_known(OCT4 teid) runs on GTPv2_Emulation_CT return boolean {
+	var integer i;
+	for (i := 0; i < sizeof(TidTable); i := i+1) {
+		if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
+			return true;
+		}
+	}
+	return false;
+}
+
 private function f_comp_by_teid(OCT4 teid) runs on GTPv2_Emulation_CT return GTP2_ConnHdlr {
 	var integer i;
 	for (i := 0; i < sizeof(TidTable); i := i+1) {
@@ -139,6 +149,16 @@
 	mtc.stop;
 }
 
+private function f_imsi_known(hexstring imsi) runs on GTPv2_Emulation_CT return boolean {
+	var integer i;
+	for (i := 0; i < sizeof(ImsiTable); i := i+1) {
+		if (isbound(ImsiTable[i].imsi) and ImsiTable[i].imsi == imsi) {
+			return true;
+		}
+	}
+	return false;
+}
+
 private function f_comp_by_imsi(hexstring imsi) runs on GTPv2_Emulation_CT return GTP2_ConnHdlr {
 	var integer i;
 	for (i := 0; i < sizeof(ImsiTable); i := i+1) {
@@ -540,30 +560,24 @@
 	/* route inbound GTP2-C based on TEID, SEQ or IMSI */
 	[] GTP2C.receive(Gtp2cUnitdata:?) -> value g2c_ud {
 		var template hexstring imsi_t := f_gtp2c_extract_imsi(g2c_ud.gtpc);
-		if (not ispresent(g2c_ud.gtpc.tEID) or g2c_ud.gtpc.tEID == int2oct(0, 4)) {
-			/* if this is a response, route by SEQ */
-			if (match(g2c_ud.gtpc, tr_PDU_GTP2C_msgtypes(gtp2_responses))
-			    and f_seq_known(g2c_ud.gtpc.sequenceNumber)) {
-				vc_conn := f_comp_by_seq(g2c_ud.gtpc.sequenceNumber);
-				CLIENT.send(g2c_ud.gtpc) to vc_conn;
-			} else {
-				SendToUdMsgTable(g2c_ud);
-				TEID0.send(g2c_ud.gtpc);
-			}
-		} else if (ispresent(g2c_ud.gtpc.tEID) and g2c_ud.gtpc.tEID != int2oct(0, 4)) {
-			vc_conn := f_comp_by_teid(g2c_ud.gtpc.tEID);
-			CLIENT.send(g2c_ud.gtpc) to vc_conn;
-		} else if (isvalue(imsi_t)) {
+		if (isvalue(imsi_t) and f_imsi_known(valueof(imsi_t))) {
 			vc_conn := f_comp_by_imsi(valueof(imsi_t));
 			CLIENT.send(g2c_ud.gtpc) to vc_conn;
+		} else if ((ispresent(g2c_ud.gtpc.tEID) and g2c_ud.gtpc.tEID != '00000000'O)
+			   and f_teid_known(g2c_ud.gtpc.tEID)) {
+			vc_conn := f_comp_by_teid(g2c_ud.gtpc.tEID);
+			CLIENT.send(g2c_ud.gtpc) to vc_conn;
+		} else if ((not ispresent(g2c_ud.gtpc.tEID) or g2c_ud.gtpc.tEID == '00000000'O)
+			   and f_teid_known('00000000'O)) {
+			vc_conn := f_comp_by_teid(g2c_ud.gtpc.tEID);
+			CLIENT.send(g2c_ud.gtpc) to vc_conn;
+		/* if this is a response, route by SEQ: */
+		} else if (match(g2c_ud.gtpc, tr_PDU_GTP2C_msgtypes(gtp2_responses))
+			   and f_seq_known(g2c_ud.gtpc.sequenceNumber)) {
+			vc_conn := f_comp_by_seq(g2c_ud.gtpc.sequenceNumber);
+			CLIENT.send(g2c_ud.gtpc) to vc_conn;
 		} else {
-			/* Send to all clients */
-			var integer i;
-			for (i := 0; i < sizeof(TidTable); i := i+1) {
-				if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
-					CLIENT.send(g2c_ud.gtpc) to TidTable[i].vc_conn;
-				}
-			}
+			SendToUdMsgTable(g2c_ud);
 		}
 
 		/* remove sequence number if response was received */