blob: dcf36461631a39278621b99f87622b3c08dbd53d [file] [log] [blame]
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +02001/* Component implementing a IMS server towards Asterisk's IMS UE
2 * (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
3 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
4 * All rights reserved.
5 *
6 * Released under the terms of GNU General Public License, Version 2 or
7 * (at your option) any later version.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11module IMS_ConnectionHandler {
12
13import from TCCOpenSecurity_Functions all;
14import from General_Types all;
15import from Osmocom_Types all;
16import from Native_Functions all;
17import from Misc_Helpers all;
18
Pau Espin Pedrola674d612024-05-14 19:56:33 +020019/* the PIPE asp port allows us to interact with ip xfrm via stdin/stdout */
20import from PIPEasp_PortType all;
21import from PIPEasp_Types all;
22import from PIPEasp_Templates all;
23
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020024import from SDP_Types all;
25import from SDP_Templates all;
26
27import from SIP_Emulation all;
28import from SIPmsg_Types all;
29import from SIP_Templates all;
30
Pau Espin Pedrola674d612024-05-14 19:56:33 +020031
32modulepar {
33 charstring mp_ipsec_setup_script_path := "./IMS_ipsec_setup.sh";
34}
35
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020036const char c_sip_server_name := "osmo-ttcn3-hacks/0.23";
37
38
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020039type port IMSCoord_PT message
40{
41 inout charstring;
42} with { extension "internal" };
43
44const charstring IMS_COORD_CMD_REGISTERED := "COORD_CMD_REGISTERED";
45
46type component IMS_ConnHdlr extends SIP_ConnHdlr {
47 var charstring g_name;
48 var IMS_ConnHdlrPars g_pars;
49 timer g_Tguard;
50 var PDU_SIP_Request g_rx_sip_req;
51 var PDU_SIP_Response g_rx_sip_resp;
52
53 port IMSCoord_PT COORD;
Pau Espin Pedrola674d612024-05-14 19:56:33 +020054 port PIPEasp_PT PIPE;
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020055}
56type record of IMS_ConnHdlr IMS_ConnHdlrList;
57
58type record IMS_ConnHdlrPars {
59 float t_guard,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020060 charstring realm,
61 charstring local_sip_host,
62 uint16_t local_sip_port,
63 charstring remote_sip_host optional,
64 uint16_t remote_sip_port optional,
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020065 charstring user,
66 charstring display_name,
67 charstring password,
Pau Espin Pedrola674d612024-05-14 19:56:33 +020068 charstring nonce,
69 charstring ipsec_auth_key,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020070 integer ipsec_local_spi_c,
71 integer ipsec_local_spi_s,
72 integer ipsec_remote_spi_c optional,
73 integer ipsec_remote_spi_s optional,
Pau Espin Pedrola674d612024-05-14 19:56:33 +020074 uint16_t ipsec_remote_port_c optional,
75 uint16_t ipsec_remote_port_s optional,
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020076 SipUrl registrar_sip_req_uri,
77 SipAddr registrar_sip_record,
78 CallidString registrar_sip_call_id,
79 integer registrar_sip_seq_nr,
80 Via local_via,
81 SipUrl local_sip_url_ext,
82 SipAddr local_sip_record,
83 Contact local_contact,
84 IMS_CallPars cp optional
85}
86type record of IMS_ConnHdlrPars IMS_ConnHdlrParsList;
87
88type record IMS_CallParsMT {
89 /* Whether to wait for COORD.receive(COORD_CMD_PICKUP) before accepting the call. */
90 boolean wait_coord_cmd_pickup,
91 /* Whether to expect CANCEL instead of ACK as answer to our OK */
92 boolean exp_cancel
93}
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +020094template (value) IMS_CallParsMT t_IMS_CallParsMT := {
95 wait_coord_cmd_pickup := false,
96 exp_cancel := false
97}
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +020098
99type record IMS_CallPars {
100 SipAddr calling optional,
101 SipAddr called optional,
102
103 SipAddr from_addr optional,
104 SipAddr to_addr optional,
105
106 CallidString sip_call_id,
107 integer sip_seq_nr,
108 charstring sip_body optional,
109
110 charstring local_rtp_addr,
111 uint16_t local_rtp_port,
112
113 SDP_Message peer_sdp optional,
114 IMS_CallParsMT mt
115}
116
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200117template (value) IMS_CallPars t_IMS_CallPars(charstring local_rtp_addr,
118 uint16_t local_rtp_port := 0,
119 template (omit) SipAddr calling := omit,
120 template (omit) SipAddr called := omit) := {
121 calling := calling,
122 called := called,
123 from_addr := omit,
124 to_addr := omit,
125 sip_call_id := hex2str(f_rnd_hexstring(15)),
126 sip_seq_nr := f_sip_rand_seq_nr(),
127 sip_body := omit,
128 local_rtp_addr := local_rtp_addr,
129 local_rtp_port := local_rtp_port,
130 peer_sdp := omit,
131 mt := t_IMS_CallParsMT
132}
133
134template (value) IMS_ConnHdlrPars t_IMS_Pars(charstring local_sip_host,
135 uint16_t local_sip_port,
136 charstring user,
137 charstring display_name := "Anonymous",
138 charstring password := "secret",
139 template (omit) IMS_CallPars cp := omit) := {
140 t_guard := 30.0,
141 realm := local_sip_host,
142 local_sip_host := local_sip_host,
143 local_sip_port := local_sip_port,
144 remote_sip_host := omit,
145 remote_sip_port := omit,
146 user := user,
147 display_name := f_sip_str_quote(display_name),
148 password := password,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200149 /* The Nonce field is the Base64 encoded version of the RAND value and concatenated with the AUTN: */
150 nonce := "FJh2MfZfjjeIoHmLbrzQjvbhmnzLAoAAoGsZyVRFFuU=",
151 ipsec_auth_key := "0x5238297dfcca759bd05d48ff49bc63fa00000000",
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200152 ipsec_local_spi_c := 4142,
153 ipsec_local_spi_s := 4143,
154 ipsec_remote_spi_c := omit,
155 ipsec_remote_spi_s := omit,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200156 ipsec_remote_port_c := omit,
157 ipsec_remote_port_s := omit,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200158 registrar_sip_req_uri := valueof(ts_SipUrlHost(local_sip_host)),
159 registrar_sip_record := ts_SipAddr(ts_HostPort(local_sip_host),
160 ts_UserInfo(user),
161 f_sip_str_quote(display_name)),
162 registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & local_sip_host,
163 registrar_sip_seq_nr := f_sip_rand_seq_nr(),
164 local_via := ts_Via_from(ts_HostPort(local_sip_host, local_sip_port)),
165 local_sip_url_ext := ts_SipUrl(ts_HostPort(local_sip_host, local_sip_port),
166 ts_UserInfo(user)),
167 local_sip_record := ts_SipAddr(ts_HostPort(local_sip_host),
168 ts_UserInfo(user)),
169 local_contact := valueof(ts_Contact({
170 ts_ContactAddress(
171 ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort(
172 local_sip_host,
173 local_sip_port),
174 ts_UserInfo(user))),
175 omit)
176 })),
177 cp := cp
178}
179
180private altstep as_Tguard() runs on IMS_ConnHdlr {
181 [] g_Tguard.timeout {
182 setverdict(fail, "Tguard timeout");
183 mtc.stop;
184 }
185}
186
187type function ims_void_fn(charstring id) runs on IMS_ConnHdlr;
188function f_ims_handler_init(ims_void_fn fn, charstring id, IMS_ConnHdlrPars pars)
189runs on IMS_ConnHdlr {
190 g_name := id;
191 g_pars := pars;
192 g_Tguard.start(pars.t_guard);
193 activate(as_Tguard());
194
195 /* call the user-supied test case function */
196 fn.apply(id);
197}
198
199private altstep as_SIP_fail_req(charstring exp_msg_str := "") runs on IMS_ConnHdlr
200{
201 var PDU_SIP_Request sip_req;
202 [] SIP.receive(PDU_SIP_Request:?) -> value sip_req {
203 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
204 log2str(g_name & ": Received unexpected SIP Req message := ", sip_req, "\nvs exp := ", exp_msg_str));
205 }
206}
207
208private altstep as_SIP_fail_resp(charstring exp_msg_str := "") runs on IMS_ConnHdlr
209{
210 var PDU_SIP_Response sip_resp;
211 [] SIP.receive(PDU_SIP_Response:?) -> value sip_resp {
212 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
213 log2str(g_name & ": Received unexpected SIP Resp message := ", sip_resp, "\nvs exp := ", exp_msg_str));
214 }
215}
216
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200217/* HTTP Digest Authentication Using AKA (AKAv1-MD5): RFC 3310 */
218function f_tr_Authorization_AKAv1MD5(WwwAuthenticate www_authenticate,
219 charstring username,
220 charstring uri,
221 integer nc_int := 1)
222return template (present) Authorization {
223 var CommaParam_List digestCln;
224 var template (present) Authorization authorization;
225 var template (present) Credentials cred;
226 var template (omit) GenericParam rx_param;
227
228 digestCln := www_authenticate.challenge[0].digestCln;
229
230 var charstring algorithm := f_sip_param_get_value_present_or_fail(digestCln, "algorithm");
231 var charstring realm := f_sip_param_get_value_present_or_fail(digestCln, "realm");
232 var charstring nonce := f_sip_param_get_value_present_or_fail(digestCln, "nonce");
233
234 var template (present) CommaParam_List digestResponse := superset(
235 tr_Param("username", f_sip_str_quote(username)),
236 tr_Param("realm", f_sip_str_quote(realm)),
237 tr_Param("nonce", f_sip_str_quote(nonce)),
238 tr_Param("uri", f_sip_str_quote(uri)),
239 tr_Param("response", ?),
240 tr_Param("algorithm", algorithm),
241 tr_Param("qop", "auth"),
242 tr_Param("cnonce", ?),
243 tr_Param("nc", ?)
244 );
245 cred := tr_Credentials_DigestResponse(digestResponse);
246 authorization := tr_Authorization(cred);
247 return authorization;
248}
249
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200250private function f_ims_validate_register_contact(Contact rx_contact)
251{
252/* IMS contact shows up like this:
253 * Contact: <sip:8adf9f3d-9342-4060-aa4f-a909f37fd6f6@192.168.101.2:5060>;+g.3gpp.accesstype="cellular2";video;audio;+g.3gpp.smsip;+g.3gpp.nw-init-ussi;+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel";+sip.instance="<urn:gsma:imei:35589811-338445-0>"
254 */
255 /* TODO: "that the UE must include the IMS Communication Service Identifier (ICSI)
256in the contact: header to indicate IMS Multimedia Telephony." */
257 /* TODO: "The UE must include an IMEI URN in the +sip.instance header field
258parameter of the contact: header." */
259 /* TODO: "If the UE supports SMS over IP, it must include the feature tag
260“+g.3gpp.smsip” in the contact: header." */
261 /* TODO: "If the UE supports conversational audio and video service, then this must
262be indicated by adding a “video” media feature tag to the contact: header." */
263}
264
265private function f_ims_parse_security_client(Security_client security_client) runs on IMS_ConnHdlr
266{
267 var boolean found := false;
268 for (var integer i := 0; i < lengthof(security_client.sec_mechanism_list); i := i + 1) {
269 var Security_mechanism sec_mec := security_client.sec_mechanism_list[i];
270 if (sec_mec.mechanism_name != "ipsec-3gpp") {
271 log("Skipping Security Mechansim: ", sec_mec.mechanism_name);
272 continue;
273 }
274 var SemicolonParam_List sec_pars := sec_mec.mechanism_params;
275 var charstring par_val;
276 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "alg");
277 if (par_val != "hmac-sha-1-96") {
278 log("Skipping Security Mechansim Algo: ", par_val);
279 continue;
280 }
281 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "spi-c");
282 g_pars.ipsec_remote_spi_c := str2int(par_val);
283 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "spi-s");
284 g_pars.ipsec_remote_spi_s := str2int(par_val);
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200285 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "port-c");
286 g_pars.ipsec_remote_port_c := str2int(par_val);
287 par_val := f_sip_param_get_value_present_or_fail(sec_pars, "port-s");
288 g_pars.ipsec_remote_port_s := str2int(par_val);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200289 found := true;
290 break;
291 }
292
293 if (not found) {
294 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
295 log2str(g_name & "alg=hmac-sha-1-96 not found: ", security_client));
296 }
297
298 log("ipsec: remote_spi_c=", g_pars.ipsec_remote_spi_c, " remote_spi_s=", g_pars.ipsec_remote_spi_s,
299 "local_spi_c=", g_pars.ipsec_local_spi_c, " local_spi_s=", g_pars.ipsec_local_spi_s);
300}
301
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200302private function f_IMS_exec_sync(charstring cmdline, template (present) integer rc := 0)
303 runs on IMS_ConnHdlr return ASP_PResult {
304 var ASP_PResult res;
305
306 map(self:PIPE, system:PIPE);
307 res := f_PIPEasp_exec_sync_PResult(PIPE, cmdline, tr_PResult(?, ?, rc));
308 unmap(self:PIPE, system:PIPE);
309
310 return res;
311}
312
313private function f_ims_setup_ipsec() runs on IMS_ConnHdlr
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200314{
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200315 var ASP_PResult res;
316
317 var charstring cmd := mp_ipsec_setup_script_path & " " &
318 g_pars.local_sip_host & " " &
319 int2str(g_pars.local_sip_port) & " " & int2str(g_pars.ipsec_local_spi_c) & " " &
320 int2str(g_pars.local_sip_port) & " " & int2str(g_pars.ipsec_local_spi_s) & " " &
321 g_pars.remote_sip_host & " " &
322 int2str(g_pars.ipsec_remote_port_c) & " " & int2str(g_pars.ipsec_remote_spi_c) & " " &
323 int2str(g_pars.ipsec_remote_port_s) & " " & int2str(g_pars.ipsec_remote_spi_s) & " " &
324 g_pars.ipsec_auth_key;
325
326 res := f_IMS_exec_sync(cmd);
327
328 /* Debug applied rules: */
329 /*
330 res := f_IMS_exec_sync("ip xfrm state");
331 log("ip-xfrm-state Result-Stdout: " & res.stdout);
332
333 res := f_IMS_exec_sync("ip xfrm policy");
334 log("ip-xfrm-policy Result-Stdout: " & res.stdout);
335 */
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200336}
337
338/* Peer is calling us, accept it: */
339altstep as_IMS_register(boolean exp_update_to_direct_rtp := true,
340 boolean fail_others := true) runs on IMS_ConnHdlr
341{
342 var template (present) PDU_SIP_Request exp_req :=
343 tr_SIP_REGISTER(g_pars.registrar_sip_req_uri,
344 ?,
345 tr_SipAddr(),
346 tr_SipAddr(),
347 tr_Via_from(?),
348 require := tr_Require(superset("sec-agree")),
349 security_client := tr_Security_client(superset(tr_Security_mechanism("ipsec-3gpp",
350 superset(tr_Param("alg","hmac-sha-1-96"))))),
351 supported := tr_Supported(superset("path", "sec-agree")));
352 var charstring sip_expect_str := log2str(exp_req);
353
354 [] SIP.receive(exp_req) -> value g_rx_sip_req {
355 var template (value) PDU_SIP_Response tx_resp;
356 var Via via;
357 var CallidString sip_call_id;
358 var Contact contact;
359 var template (value) SipAddr from_addr;
360 var template (value) SipAddr to_addr;
361 var template (value) CommaParam_List digestCln ;
362 var template (value) WwwAuthenticate wwwAuthenticate;
363 var template (value) Security_server security_server;
364 var template (value) Server server_name := ts_Server({c_sip_server_name});
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200365 var template (value) Require require := ts_Require({"sec-agree"});
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200366 var template (value) Supported supported := ts_Supported({"sec-agree"});
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200367 var template (present) Authorization authorization;
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200368 var integer sip_seq_nr;
369 var charstring tx_sdp;
370
371 sip_call_id := g_rx_sip_req.msgHeader.callId.callid;
372 via := g_rx_sip_req.msgHeader.via;
373 via.viaBody[0].viaParams := f_sip_param_set(via.viaBody[0].viaParams, "rport", "1234"); /* TODO: set remote src port of the REGISTER */
374 from_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.fromField.addressField,
375 g_rx_sip_req.msgHeader.fromField.fromParams);
376 to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
377 g_rx_sip_req.msgHeader.toField.toParams);
378 sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
379
380 contact := g_rx_sip_req.msgHeader.contact;
381 f_ims_validate_register_contact(contact);
382
383 /* TODO: Validate "Expires" is 600000 */
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200384
385 /* Tx 100 Tyring */
386 tx_resp := ts_SIP_Response_Trying(sip_call_id,
387 from_addr,
388 to_addr,
389 via,
390 sip_seq_nr,
391 "REGISTER",
392 allow := omit,
393 server := server_name,
394 userAgent := omit);
395 SIP.send(tx_resp);
396
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200397 g_pars.remote_sip_host := valueof(contact.contactBody.contactAddresses[0].addressField.nameAddr.addrSpec.hostPort.host);
398 f_ims_parse_security_client(g_rx_sip_req.msgHeader.security_client);
399 f_ims_setup_ipsec();
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200400
401 to_addr.params := f_sip_param_set(to_addr.params, "tag", f_sip_rand_tag());
402
403 digestCln := {
404 ts_Param("realm", f_sip_str_quote(g_pars.realm)),
405 ts_Param("qop", f_sip_str_quote("auth")),
406 ts_Param("algorithm", "AKAv1-MD5"),
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200407 ts_Param("nonce", f_sip_str_quote(g_pars.nonce))
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200408 /* "opaque not needed in IMS "*/
409 };
410 wwwAuthenticate := ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
411
412 /* Security-Server: ipsec-3gpp;q=0.1;prot=esp;mod=trans;spi-c=4096;spi-s=4097;port-c=5104;port-s=6104;alg=hmac-sha-1-96;ealg=null */
413 var template (value) SemicolonParam_List sec_params := {
414 ts_Param("q", "0.1"),
415 ts_Param("prot", "esp"),
416 ts_Param("mod", "trans"),
417 ts_Param("spi-c", int2str(g_pars.ipsec_local_spi_c)),
418 ts_Param("spi-s", int2str(g_pars.ipsec_local_spi_s)),
419 ts_Param("port-c", int2str(g_pars.local_sip_port)),
420 ts_Param("port-s", int2str(g_pars.local_sip_port)),
421 ts_Param("alg", "hmac-sha-1-96"),
422 ts_Param("ealg", "null")
423 };
424 security_server := ts_Security_server({
425 ts_Security_mechanism("ipsec-3gpp", sec_params)
426 });
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200427
428 /* Tx 401 Unauthorized */
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200429 tx_resp := ts_SIP_Response_Unauthorized(sip_call_id,
430 from_addr,
431 to_addr,
432 via,
433 wwwAuthenticate,
434 sip_seq_nr,
435 "REGISTER",
436 security_server := security_server,
437 server := server_name,
438 supported := supported,
439 userAgent := omit);
440 SIP.send(tx_resp);
441
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200442 /* Now we should receive a new REGISTER over ipsec: */
443
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200444 /* TODO: Generate expected Authoritzation based on AKAv1-MD5: */
445 /*authorization := f_sip_digest_gen_Authorization(valueof(wwwAuthenticate),
446 g_pars.user, g_pars.password,
447 "REGISTER",
448 f_sip_SipUrl_to_str(g_pars.registrar_sip_record.addr.nameAddr.addrSpec))
449 */
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200450 authorization := f_tr_Authorization_AKAv1MD5(valueof(wwwAuthenticate),
451 g_pars.user & "@" & g_pars.realm,
452 f_sip_SipUrl_to_str(g_pars.registrar_sip_record.addr.nameAddr.addrSpec));
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200453 /* TODO: match Authorization from above: */
454 exp_req :=
455 tr_SIP_REGISTER(g_pars.registrar_sip_req_uri,
456 ?,
457 tr_SipAddr(),
458 tr_SipAddr(),
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200459 tr_Via_from(?),
460 authorization := authorization);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200461 SIP.receive(exp_req) -> value g_rx_sip_req;
462
463 sip_call_id := g_rx_sip_req.msgHeader.callId.callid;
464 via := g_rx_sip_req.msgHeader.via;
465 from_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.fromField.addressField,
466 g_rx_sip_req.msgHeader.fromField.fromParams);
467 to_addr := ts_SipAddr_from_Addr_Union(g_rx_sip_req.msgHeader.toField.addressField,
468 g_rx_sip_req.msgHeader.toField.toParams);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200469 sip_seq_nr := g_rx_sip_req.msgHeader.cSeq.seqNumber;
470
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200471 /* Tx 100 Trying */
472 tx_resp := ts_SIP_Response_Trying(sip_call_id,
473 from_addr,
474 to_addr,
475 via,
476 sip_seq_nr,
477 "REGISTER",
478 allow := omit,
479 server := server_name,
480 userAgent := omit);
481 SIP.send(tx_resp);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200482
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200483 /* Tx 200 OK */
484 to_addr.params := f_sip_param_set(to_addr.params, "tag", f_sip_rand_tag());
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200485 tx_resp := ts_SIP_Response(sip_call_id,
486 from_addr,
487 to_addr,
488 "REGISTER", 200,
489 sip_seq_nr,
490 "OK",
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200491 via,
492 require := require,
493 server := server_name,
494 supported := supported,
495 userAgent := omit);
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +0200496 SIP.send(tx_resp);
497 }
498 [fail_others] as_SIP_fail_resp(sip_expect_str);
499 [fail_others] as_SIP_fail_req(sip_expect_str);
500
501}
502
Pau Espin Pedrolac8a0542024-04-19 17:30:57 +0200503}