ggsn: Validate charging reported values

Change-Id: I497309bb0b30c61bdb00e0c08f18294ecd4dd485
diff --git a/library/DIAMETER_Templates.ttcn b/library/DIAMETER_Templates.ttcn
index 855358d..4b17ac5 100644
--- a/library/DIAMETER_Templates.ttcn
+++ b/library/DIAMETER_Templates.ttcn
@@ -11,6 +11,7 @@
 
 import from DIAMETER_Types all;
 import from Osmocom_Types all;
+import from Misc_Helpers all;
 
 /* https://www.iana.org/assignments/aaa-parameters/aaa-parameters.xhtml#aaa-parameters-4 */
 type enumerated DIAMETER_Resultcode {
@@ -1611,4 +1612,100 @@
 			tr_AVP_OriginStateId(state_id)
 	));
 
+function f_DIAMETER_get_avp(PDU_DIAMETER pdu, template (present) AVP_Code avp_code)
+return template (omit) AVP
+{
+	var integer i;
+
+	for (i := 0; i < lengthof(pdu.avps); i := i+1) {
+		if (not ispresent(pdu.avps[i].avp)) {
+			continue;
+		}
+		var AVP_Header hdr := pdu.avps[i].avp.avp_header;
+		if (match(hdr.avp_code, avp_code)) {
+			return pdu.avps[i].avp;
+		}
+	}
+	return omit;
+}
+function f_DIAMETER_get_avp_or_fail(PDU_DIAMETER pdu, template (present) AVP_Code avp_code)
+return AVP
+{
+	var template (omit) AVP avp;
+	avp := f_DIAMETER_get_avp(pdu, avp_code);
+	if (istemplatekind(avp, "omit")) {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+			log2str("AVP ", avp_code, " not found in ", pdu));
+	}
+	return valueof(avp);
+}
+
+function f_AVP_Grouped_get_avp(AVP_Grouped avp_grp, template (present) AVP_Code avp_code)
+return template (omit) AVP
+{
+	var integer i;
+
+	for (i := 0; i < lengthof(avp_grp); i := i+1) {
+		if (not ispresent(avp_grp[i].avp)) {
+			continue;
+		}
+		var AVP_Header hdr := avp_grp[i].avp.avp_header;
+		if (match(hdr.avp_code, avp_code)) {
+			return avp_grp[i].avp;
+		}
+	}
+	return omit;
+}
+function f_AVP_Grouped_get_avp_or_fail(AVP_Grouped avp_grp, template (present) AVP_Code avp_code)
+return AVP
+{
+	var template (omit) AVP avp;
+	avp := f_AVP_Grouped_get_avp(avp_grp, avp_code);
+	if (istemplatekind(avp, "omit")) {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+			log2str("AVP ", avp_code, " not found in ", avp_grp));
+	}
+	return valueof(avp);
+}
+
+function f_validate_gy_cc_report(PDU_DIAMETER rx_dia, template (present) DCA_3GPP_Reporting_Reason repreason_exp := ?,
+				 template (present) integer cc_time_exp := ?,
+				 template (present) integer cc_in_oct_exp := ?,
+				 template (present) integer cc_out_oct_exp := ?)
+{
+	var AVP multi_services_cc, used_service_unit;
+	var AVP_Grouped multi_services_cc_data, used_service_unit_data;
+	var AVP repreason, cc_time, cc_in_oct, cc_out_oct;
+
+	multi_services_cc := f_DIAMETER_get_avp_or_fail(rx_dia, c_AVP_Code_DCC_NONE_Multiple_Services_Credit_Control);
+	multi_services_cc_data := valueof(multi_services_cc.avp_data.avp_DCC_NONE_Multiple_Services_Credit_Control);
+
+	repreason := f_AVP_Grouped_get_avp_or_fail(multi_services_cc_data, c_AVP_Code_DCA_3GPP_Reporting_Reason);
+	if (not match(repreason.avp_data.avp_DCA_3GPP_Reporting_Reason, repreason_exp)) {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+			log2str("3GPP-Reporting-Reason mismatch ", repreason, " vs exp ", repreason_exp));
+	}
+
+	used_service_unit := f_AVP_Grouped_get_avp_or_fail(multi_services_cc_data, c_AVP_Code_DCC_NONE_Used_Service_Unit);
+	used_service_unit_data := valueof(used_service_unit.avp_data.avp_DCC_NONE_Used_Service_Unit);
+
+	cc_time := f_AVP_Grouped_get_avp_or_fail(used_service_unit_data, c_AVP_Code_DCC_NONE_CC_Time);
+	if (not match(oct2int(cc_time.avp_data.avp_DCC_NONE_CC_Time), cc_time_exp)) {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+			log2str("3GPP-CC-Time mismatch ", cc_time, " vs exp ", cc_time_exp));
+	}
+
+	cc_in_oct := f_AVP_Grouped_get_avp_or_fail(used_service_unit_data, c_AVP_Code_DCC_NONE_CC_Input_Octets);
+	if (not match(oct2int(cc_in_oct.avp_data.avp_DCC_NONE_CC_Input_Octets), cc_in_oct_exp)) {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+			log2str("3GPP-CC-Input-Octets mismatch ", cc_in_oct, " vs exp ", cc_in_oct_exp));
+	}
+
+	cc_out_oct := f_AVP_Grouped_get_avp_or_fail(used_service_unit_data, c_AVP_Code_DCC_NONE_CC_Output_Octets);
+	if (not match(oct2int(cc_out_oct.avp_data.avp_DCC_NONE_CC_Output_Octets), cc_out_oct_exp)) {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+			log2str("3GPP-CC-Output-Octets mismatch ", cc_out_oct, " vs exp ", cc_out_oct_exp));
+	}
+}
+
 }