libosmosim: class_tables: Resolve conflicting CLA=8x INS=F2 definitions

In their infinite wisdom, GlobalPlatform re-defined the CLA 8x / INS F2 command
alreay specified by ETSI TS 102 221.  This wouldn't be as bads if they
had the same "Case".  However, ETSI has case 2 while GP has case 4.

Lucikly, the P1 coding of ETSI [so far] states all the four upper bits
must be 0, while GP always has one of those bits set.

Before this patch, it is possible that a Modem/Phone will send an 8xF2
command and intends it as a GlobalPlatform command (with Lc > 0 and
command data portion), while this code assumes it is an ETSI UICC
command with Lc=0 and hence no command data portion.  This will make
communication break when using simtrace2 'cardem'.

Change-Id: I8dd317ef8f942542e412b18c834a0467c51291c3
Related: SYS#6865
Related: https://lists.osmocom.org/hyperkitty/list/simtrace@lists.osmocom.org/thread/HPRTPGPZITHHASCJISCBAKHGBFZCFANP/
diff --git a/src/sim/class_tables.c b/src/sim/class_tables.c
index 29c1e40..29ef2d7 100644
--- a/src/sim/class_tables.c
+++ b/src/sim/class_tables.c
@@ -187,6 +187,16 @@
 		default:
 			return 3;
 		}
+		break;
+	case 0xF2:
+		/* in their infinite wisdom, GlobalPlatform re-defined the CLA 8x / INS F2 command, so one can
+		 * take a guess if it's GlobalPlatform or ETSI.  Lucikly, the P1 coding of ETSI [so far]
+		 * states all the four upper bits must be 0, while GP always has one of those bits set */
+		if (p1 & 0xF0)
+			return 4; /* GlobalPlatform v2.2 11.4.2 */
+		else
+			return 2; /* ETSI TS 102 221 V16.2.0 11.1.2 */
+		break;
 	}
 	return 0;
 }
@@ -217,7 +227,7 @@
 	[0xE2]		= 0x80,	/* STORE DATA */
 	[0xCA]		= 4,	/* GET DATA */
 	[0xCB]		= 4,	/* GET DATA */
-	[0xF2]		= 4,	/* GET STATUS */
+	[0xF2]		= 0x80,	/* GET STATUS */
 	[0xE6]		= 4,	/* INSTALL */
 	[0xE8]		= 4,	/* LOAD */
 	[0xD8]		= 4,	/* PUT KEY */
@@ -246,6 +256,12 @@
 		.helper		= uicc046_cla_ins_helper,
 		.ins_tbl	= uicc_ins_tbl_046,
 	}, {
+		/* must be before uicc_ins_tbl_8ce below with same CLA+mask */
+		.cla		= 0x80,
+		.cla_mask	= 0xF0,
+		.helper		= gp_cla_ins_helper,
+		.ins_tbl	= gp_ins_tbl_8ce,
+	}, {
 		.cla		= 0x80,
 		.cla_mask	= 0xF0,
 		.ins_tbl	= uicc_ins_tbl_8ce,
@@ -258,11 +274,6 @@
 		.cla_mask	= 0xF0,
 		.ins_tbl	= uicc_ins_tbl_8ce,
 	}, {
-		.cla		= 0x80,
-		.cla_mask	= 0xF0,
-		.helper		= gp_cla_ins_helper,
-		.ins_tbl	= gp_ins_tbl_8ce,
-	}, {
 		.cla		= 0xC0,
 		.cla_mask	= 0xF0,
 		.helper		= gp_cla_ins_helper,
@@ -308,6 +319,12 @@
 		.helper		= uicc046_cla_ins_helper,
 		.ins_tbl	= uicc_ins_tbl_046,
 	}, {
+		/* must be before uicc_ins_tbl_8ce below with same CLA+mask */
+		.cla		= 0x80,
+		.cla_mask	= 0xF0,
+		.helper		= gp_cla_ins_helper,
+		.ins_tbl	= gp_ins_tbl_8ce,
+	}, {
 		.cla		= 0x80,
 		.cla_mask	= 0xF0,
 		.ins_tbl	= uicc_ins_tbl_8ce,
diff --git a/tests/sim/sim_test.c b/tests/sim/sim_test.c
index 2e2eec5..9a52af4 100644
--- a/tests/sim/sim_test.c
+++ b/tests/sim/sim_test.c
@@ -27,6 +27,8 @@
 const uint8_t uicc_tprof_wrong_class[] = { 0x00, 0x10, 0x00, 0x00, 0x02, 0x01, 0x02 };
 const uint8_t uicc_read[] = { 0x00, 0xB0, 0x00, 0x00, 0x10 };
 const uint8_t uicc_upd[] = { 0x00, 0xD6, 0x00, 0x00, 0x02, 0x01, 0x02 };
+const uint8_t uicc_get_status[] = { 0x80, 0xf2, 0x00, 0x02, 0x10 };
+const uint8_t euicc_m2m_get_status[] = { 0x81, 0xf2, 0x40, 0x02, 0x02, 0x4f, 0x00 };
 
 #define APDU_CASE_ASSERT(x, y)				\
 	do {						\
@@ -45,6 +47,8 @@
 	APDU_CASE_ASSERT(uicc_tprof_wrong_class, 0);
 	APDU_CASE_ASSERT(uicc_read, 2);
 	APDU_CASE_ASSERT(uicc_upd, 3);
+	APDU_CASE_ASSERT(uicc_get_status, 2);
+	APDU_CASE_ASSERT(euicc_m2m_get_status, 4);
 }
 
 int main(int argc, char **argv)
diff --git a/tests/sim/sim_test.ok b/tests/sim/sim_test.ok
index 7d3f986..cac59ba 100644
--- a/tests/sim/sim_test.ok
+++ b/tests/sim/sim_test.ok
@@ -4,3 +4,5 @@
 Testing uicc_tprof_wrong_class
 Testing uicc_read
 Testing uicc_upd
+Testing uicc_get_status
+Testing euicc_m2m_get_status