asterisk: Use Action PJSIPAccessNetworkInfo

Validate P-Access-Network-Info should only be present in 2nd REGISTER
sent over ipsec.

Change-Id: I2759d12caeaca81a9224997a29541c325d65fe30
diff --git a/asterisk/AMI_Functions.ttcn b/asterisk/AMI_Functions.ttcn
index 9fbe973..4969905 100644
--- a/asterisk/AMI_Functions.ttcn
+++ b/asterisk/AMI_Functions.ttcn
@@ -28,6 +28,7 @@
 const charstring AMI_FIELD_ACTION := "Action";
 const charstring AMI_FIELD_ACTION_ID := "ActionID";
 const charstring AMI_FIELD_EVENT := "Event";
+const charstring AMI_FIELD_INFO := "Info";
 const charstring AMI_FIELD_USERNAME := "Username";
 const charstring AMI_FIELD_SECRET := "Secret";
 const charstring AMI_FIELD_RESPONSE := "Response";
@@ -79,6 +80,8 @@
 template (value) AMI_Field
 ts_AMI_Field_Event(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_EVENT, val);
 template (value) AMI_Field
+ts_AMI_Field_Info(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_INFO, val);
+template (value) AMI_Field
 ts_AMI_Field_Username(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_USERNAME, val);
 template (value) AMI_Field
 ts_AMI_Field_Secret(template (value) charstring val) := ts_AMI_Field(AMI_FIELD_SECRET, val);
@@ -93,6 +96,8 @@
 template (present) AMI_Field
 tr_AMI_Field_Event(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_EVENT, val);
 template (present) AMI_Field
+tr_AMI_Field_Info(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_INFO, val);
+template (present) AMI_Field
 tr_AMI_Field_Username(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_USERNAME, val);
 template (present) AMI_Field
 tr_AMI_Field_Secret(template (present) charstring val := ?) := tr_AMI_Field(pattern @nocase AMI_FIELD_SECRET, val);
@@ -139,6 +144,23 @@
 	tr_AMI_Field_Secret(secret)
 );
 
+/* Action: PJSIPAccessNetworkInfo
+ * Registration: volte_ims
+ * Info: 3GPP-E-UTRAN-FDD; utran-cell-id-3gpp=2380100010000101
+ */
+template (value) AMI_Msg
+ts_AMI_Action_PJSIPAccessNetworkInfo(template (value) charstring registration := "volte_ims",
+				     template (value) charstring info := "",
+				     template (value) charstring action_id := "0001") := {
+	ts_AMI_Field_Action("PJSIPAccessNetworkInfo"),
+	ts_AMI_Field_ActionId(action_id),
+	ts_AMI_Field_Registration(registration),
+	ts_AMI_Field_Info(info)
+};
+function f_ami_gen_PJSIPAccessNetworkInfo_Info_EUTRAN(charstring uli_str) return charstring {
+	return "3GPP-E-UTRAN-FDD; utran-cell-id-3gpp=" & uli_str;
+}
+
 /* Action: PJSIPRegister
  * ActionID: <value>
  * Registration: volte_ims
@@ -508,6 +530,13 @@
 	f_ami_transceive_match_response_success(pt, ts_AMI_Action_Login(username, secret, reg_action_id));
 }
 
+function f_ami_action_PJSIPAccessNetworkInfo(AMI_Msg_PT pt,
+					     template (value) charstring registration,
+					     template (value) charstring info) {
+	var charstring reg_action_id := f_gen_action_id();
+	f_ami_transceive_match_response_success(pt, ts_AMI_Action_PJSIPAccessNetworkInfo(registration, info, reg_action_id));
+}
+
 function f_ami_action_PJSIPRegister(AMI_Msg_PT pt, charstring register) {
 	var charstring reg_action_id := f_gen_action_id();
 	f_ami_transceive_match_response_success(pt, ts_AMI_Action_PJSIPRegister(register, reg_action_id));
diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn
index a71bcad..df5904b 100644
--- a/asterisk/Asterisk_Tests.ttcn
+++ b/asterisk/Asterisk_Tests.ttcn
@@ -376,6 +376,12 @@
 	f_sleep(1.0);
 	/* Clear events: */
 	AMI_CLIENT.clear;
+
+	/* Announce network information, this should usually happen when UE
+	 * becomes attached to network and before IMS APN is set up: */
+	f_ami_action_PJSIPAccessNetworkInfo(AMI_CLIENT, mp_volte_ims_outbound_registration,
+					    f_ami_gen_PJSIPAccessNetworkInfo_Info_EUTRAN(pars.uli_str));
+
 	/* Trigger registration: */
 	f_ami_action_PJSIPRegister(AMI_CLIENT, mp_volte_ims_outbound_registration);
 	/* TODO: Rx "Event: AuthRequest" */
diff --git a/asterisk/IMS_ConnectionHandler.ttcn b/asterisk/IMS_ConnectionHandler.ttcn
index d1e3185..0d11922 100644
--- a/asterisk/IMS_ConnectionHandler.ttcn
+++ b/asterisk/IMS_ConnectionHandler.ttcn
@@ -66,6 +66,8 @@
 	charstring user,
 	charstring display_name,
 	charstring password,
+	/* Expected User-Location-Info in P-Access-Network-Info */
+	charstring uli_str,
 	octetstring rand,
 	octetstring autn,
 	charstring ipsec_auth_key,
@@ -148,6 +150,7 @@
 	user := user,
 	display_name := f_sip_str_quote(display_name),
 	password := password,
+	uli_str := "2380100010000101",
 	/* The Nonce field is the Base64 encoded version of the RAND value and concatenated with the AUTN: */
 	rand := '14987631f65f8e3788a0798b6ebcd08e'O,
 	autn := 'f6e19a7ccb028000a06b19c9544516e5'O,
@@ -272,6 +275,37 @@
 be indicated by adding a “video” media feature tag to the contact: header." */
 }
 
+/* Validate P-Access-Network-Info: RFC7315 6.4 */
+private function f_ims_validate_register_P_Access_Network_info(PDU_SIP_Request req,
+							       boolean exp_present := true) runs on IMS_ConnHdlr
+
+{
+	if (not exp_present) {
+		if (ispresent(g_rx_sip_req.msgHeader.p_access_network_info)) {
+			Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+						log2str(g_name & ": Received unexpected [rfc7315 6.4] P-Access-Info := ",
+						g_rx_sip_req.msgHeader.p_access_network_info));
+		}
+		return;
+	}
+
+	/* exp_present: */
+	var template (present) P_Access_Network_Info expl_tmpl :=
+		tr_P_Access_Network_Info({ tr_Access_net_spec_EUTRAN(g_pars.uli_str) });
+
+	if (not ispresent(g_rx_sip_req.msgHeader.p_access_network_info)) {
+		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+					log2str(g_name & ": Received no P-Access-Info vs exp := ",
+					expl_tmpl));
+	}
+	if (not match(g_rx_sip_req.msgHeader.p_access_network_info, expl_tmpl)) {
+				Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+							log2str(g_name & ": Received unexpected P-Access-Info := ",
+							g_rx_sip_req.msgHeader.p_access_network_info,
+							"\nvs exp := ", expl_tmpl));
+	}
+}
+
 private function f_ims_parse_security_client(Security_client security_client) runs on IMS_ConnHdlr
 {
 	var boolean found := false;
@@ -390,6 +424,16 @@
 		contact := g_rx_sip_req.msgHeader.contact;
 		f_ims_validate_register_contact(contact);
 
+		/* Validate P-Access-Network-Info: rfc7315 6.4:
+		 * "3GPP will use the P-Access-Network-Info header field to
+		 * carry relatively sensitive information like the cell ID.  Therefore,
+		 * the information MUST NOT be sent outside of the 3GPP domain.""
+		 * [...] "the sensitive information carried in the
+		 * P-Access-Network-Info header field MUST NOT be sent in any initial
+		 * unauthenticated and unprotected requests (e.g., REGISTER)."
+		 */
+		f_ims_validate_register_P_Access_Network_info(g_rx_sip_req, exp_present := false);
+
 		/* TODO: Validate "Expires" is 600000 */
 
 		/* Tx 100 Tyring */
@@ -490,6 +534,9 @@
 					userAgent := omit);
 		SIP.send(tx_resp);
 
+		/* Validate P-Access-Network-Info: */
+		f_ims_validate_register_P_Access_Network_info(g_rx_sip_req, exp_present := true);
+
 		/* Tx 200 OK */
 		to_addr.params := f_sip_param_set(to_addr.params, "tag", f_sip_rand_tag());
 		tx_resp := ts_SIP_Response(sip_call_id,