blob: d0210d1a3447bc70941b4b735146d3ce84ace07b [file] [log] [blame]
Harald Welteb0d93602018-03-20 18:09:34 +01001module SIP_Templates {
2
3import from SIPmsg_Types all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02004import from TCCConversion_Functions all;
5import from TCCOpenSecurity_Functions all;
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02006import from TCCDateTime_Functions all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02007import from Native_Functions all;
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01008import from Osmocom_Types all;
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02009import from Misc_Helpers all;
Harald Welteb0d93602018-03-20 18:09:34 +010010
11/* wrapper type to encapsulate the Addr_Union + parameter list used in From, To. ... */
12type record SipAddr {
13 Addr_Union addr,
14 SemicolonParam_List params optional
15}
16
17const charstring c_SIP_VERSION := "SIP/2.0";
18
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020019template (value) GenericParam ts_Param(template (value) charstring id,
20 template (omit) charstring paramValue := omit) := {
21 id := id,
22 paramValue := paramValue
23}
24template (present) GenericParam tr_Param(template (present) charstring id := ?,
25 template charstring paramValue := *) := {
26 id := id,
27 paramValue := paramValue
28}
29function f_ts_Param_omit(template (value) charstring id,
30 template (omit) charstring paramValue := omit)
31 return template (omit) GenericParam
32{
33 if (istemplatekind(paramValue, "omit")) {
34 return omit;
35 }
36 return ts_Param(id, paramValue);
37}
38
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010039template (value) SipUrl ts_SipUrl(template (value) HostPort host_port,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +020040 template (omit) UserInfo user_info := omit,
41 template (value) charstring scheme := "sip") := {
42 scheme := scheme,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010043 userInfo := user_info,
44 hostPort := host_port,
Harald Welteb0d93602018-03-20 18:09:34 +010045 urlParameters := omit,
46 headers := omit
47}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010048template (present) SipUrl tr_SipUrl(template (present) HostPort host_port := ?,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +020049 template UserInfo user_info := *,
50 template (present) charstring scheme := "sip") := {
51 scheme := scheme,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010052 userInfo := user_info,
53 hostPort := host_port,
Harald Welteb0d93602018-03-20 18:09:34 +010054 urlParameters := *,
55 headers := *
56}
57
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020058template (value) SipUrl ts_SipUrlHost(template (value) charstring host,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +020059 template (omit) integer portField := omit,
60 template (value) charstring scheme := "sip")
61 := ts_SipUrl(ts_HostPort(host, portField), scheme := scheme);
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +020062
63function ts_SipUrl_from_Addr_Union(template (value) Addr_Union au)
64return template (value) SipUrl {
65 if (ischosen(au.nameAddr)) {
66 return au.nameAddr.addrSpec;
67 } else { /* au.addrSpecUnion */
68 return au.addrSpecUnion;
69 }
70}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +010071
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +020072// [20.5]
73template (present) Allow tr_Allow(template Method_List methods := *) := {
74 fieldName := ALLOW_E,
75 methods := methods
76}
77template (value) Allow ts_Allow(template (omit) Method_List methods := omit) := {
78 fieldName := ALLOW_E,
79 methods := methods
80}
81
Pau Espin Pedrola674d612024-05-14 19:56:33 +020082template (present) Credentials tr_Credentials_DigestResponse(template (present) CommaParam_List digestResponse) := {
83 digestResponse := digestResponse
84}
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +020085template (value) Credentials ts_Credentials_DigestResponse(template (value) CommaParam_List digestResponse) := {
86 digestResponse := digestResponse
87}
88
89template (value) Credentials ts_Credentials_DigestResponseMD5(
90 template (value) charstring username,
91 template (value) charstring realm,
92 template (value) charstring nonce,
93 template (value) charstring uri,
94 template (value) charstring response,
95 template (value) charstring opaque,
96 template (value) charstring algorithm := "MD5",
97 template (value) charstring qop := "auth",
98 template (omit) charstring cnonce := omit,
99 template (omit) charstring nc := omit
100 ) := {
101 digestResponse := {
102 // Already added by digestResponse automatically:
103 //ts_Param("Digest", omit),
104 ts_Param("username", f_sip_str_quote(username)),
105 ts_Param("realm", f_sip_str_quote(realm)),
106 ts_Param("nonce", f_sip_str_quote(nonce)),
107 ts_Param("uri", f_sip_str_quote(uri)),
108 ts_Param("response", f_sip_str_quote(response)),
109 ts_Param("opaque", f_sip_str_quote(opaque)),
110 ts_Param("algorithm", algorithm),
111 ts_Param("qop", qop),
112 // FIXME: If "omit" is passed, these below end up in;
113 // "Dynamic test case error: Performing a valueof or send operation on a non-specific template of type @SIPmsg_Types.GenericParam"
114 f_ts_Param_omit("cnonce", f_sip_str_quote(cnonce)),
115 f_ts_Param_omit("nc", nc)
116 }
117}
118
119template (value) Credentials ts_Credentials_OtherAuth(template (value) OtherAuth otherResponse) := {
120 otherResponse := otherResponse
121}
122
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200123template (present) Authorization tr_Authorization(template (present) Credentials body) := {
124 fieldName := AUTHORIZATION_E,
125 body := body
126}
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200127template (value) Authorization ts_Authorization(template (value) Credentials body) := {
128 fieldName := AUTHORIZATION_E,
129 body := body
130}
131
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100132// [20.10]
133template (present) NameAddr tr_NameAddr(template (present) SipUrl addrSpec := ?,
134 template charstring displayName := *) := {
135 displayName := displayName,
136 addrSpec := addrSpec
Harald Welteb0d93602018-03-20 18:09:34 +0100137}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100138template (value) NameAddr ts_NameAddr(template (value) SipUrl addrSpec,
139 template (omit) charstring displayName := omit) := {
140 displayName := displayName,
141 addrSpec := addrSpec
142}
143
144template (present) Addr_Union tr_Addr_Union_NameAddr(template (present) NameAddr nameAddr := ?) := {
145 nameAddr := nameAddr
146}
147template (value) Addr_Union ts_Addr_Union_NameAddr(template (value) NameAddr nameAddr) := {
148 nameAddr := nameAddr
149}
150
151template (present) Addr_Union tr_Addr_Union_SipUrl(template (present) SipUrl sipUrl := ?) := {
152 addrSpecUnion := sipUrl
153}
154template (value) Addr_Union ts_Addr_Union_SipUrl(template (value) SipUrl sipUrl) := {
155 addrSpecUnion := sipUrl
156}
157
158
159template (present) ContactAddress tr_ContactAddress(template (present) Addr_Union addressField := ?,
160 template SemicolonParam_List contactParams := *) := {
161 addressField := addressField,
162 contactParams := contactParams
163}
164template (value) ContactAddress ts_ContactAddress(template (value) Addr_Union addressField,
165 template (omit) SemicolonParam_List contactParams := omit) := {
166 addressField := addressField,
167 contactParams := contactParams
168}
169
170template (present) Contact tr_Contact(template (present) ContactAddress_List contactAddresses := ?) := {
171 fieldName := CONTACT_E,
172 contactBody := {
173 contactAddresses := contactAddresses
174 }
175}
176template (value) Contact ts_Contact(template (value) ContactAddress_List contactAddresses) := {
177 fieldName := CONTACT_E,
178 contactBody := {
179 contactAddresses := contactAddresses
180 }
181}
182
183template (value) Contact ts_ContactWildcard := {
184 fieldName := CONTACT_E,
185 contactBody := {
186 wildcard := "*"
187 }
188}
189
190template (present) Contact tr_Contact_SipAddr(template (present) SipAddr contact_addr := ?)
191 := tr_Contact({ tr_ContactAddress(contact_addr.addr, contact_addr.params) });
192
193private function f_tr_Contact_SipAddr(template SipAddr contact_addr) return template Contact
194{
195 if (istemplatekind(contact_addr, "omit")) {
196 return omit;
197 } else if (istemplatekind(contact_addr, "*")) {
198 return *;
199 }
200 return tr_Contact_SipAddr(contact_addr);
201}
202
203template (value) Contact ts_Contact_SipAddr(template (value) SipAddr contact_addr)
204 := ts_Contact({ ts_ContactAddress(contact_addr.addr, contact_addr.params) });
205private function ts_Contact_SipAddr_omit(template (omit) SipAddr contact_addr := omit) return template (omit) Contact
206{
207 if (istemplatekind(contact_addr, "omit")) {
208 return omit;
209 }
210 return ts_Contact_SipAddr(contact_addr);
211}
212
213
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200214// [20.14]
215template (value) ContentLength ts_ContentLength(template (value) integer len := 0) := {
216 fieldName := CONTENT_LENGTH_E,
217 len := len
218}
219template (present) ContentLength tr_ContentLength(template (present) integer len := ?) := {
220 fieldName := CONTENT_LENGTH_E,
221 len := len
222}
223
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100224// [20.19]
225template (value) Expires ts_Expires(template (value) DeltaSec deltaSec := "7200") := {
226 fieldName := EXPIRES_E,
227 deltaSec := deltaSec
228}
Pau Espin Pedrol586eec52024-06-04 19:07:33 +0200229template (present) Expires tr_Expires(template (present) DeltaSec deltaSec := ?) := {
230 fieldName := EXPIRES_E,
231 deltaSec := deltaSec
232}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100233
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200234// [20.20]
235template (value) From ts_From(template (value) Addr_Union addressField,
236 template (omit) SemicolonParam_List fromParams := omit) := {
237 fieldName := FROM_E,
238 addressField := addressField,
239 fromParams := fromParams
240}
241template (present) From tr_From(template (present) Addr_Union addressField := ?,
242 template SemicolonParam_List fromParams := *) := {
243 fieldName := FROM_E,
244 addressField := addressField,
245 fromParams := fromParams
246}
247
Pau Espin Pedrol0c5c6472024-05-21 13:13:49 +0200248// [RFC3455 5.4] + 3GPP 24.229 V8.7.0
249template (present) Access_net_spec tr_Access_net_spec(template (present) charstring access_type := ?,
250 template SemicolonParam_List access_info := *) := {
251 access_type := access_type,
252 access_info := access_info
253}
254template (present) Access_net_spec tr_Access_net_spec_EUTRAN(template (present) charstring uli_str := ?) := {
255 access_type := "3GPP-E-UTRAN-FDD",
256 access_info := {tr_Param("utran-cell-id-3gpp", uli_str)}
257}
258
259// [RFC3455 5.4] + 3GPP 24.229 V8.7.0
260template (present) P_Access_Network_Info tr_P_Access_Network_Info(template (present) Access_net_spec_list access_net_specs := ?) := {
261 fieldName := P_ACCESS_NETWORK_INFO,
262 access_net_specs := access_net_specs
263}
264
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +0200265// [RFC3455 4.1]
266template (present) P_Assoc_uri_spec tr_P_Assoc_uri_spec(template (present) NameAddr p_asso_uri := ?,
267 template SemicolonParam_List ai_params := *) := {
268 p_asso_uri := p_asso_uri,
269 ai_params := ai_params
270}
271template (value) P_Assoc_uri_spec ts_P_Assoc_uri_spec(template (value) NameAddr p_asso_uri,
272 template (omit) SemicolonParam_List ai_params := omit) := {
273 p_asso_uri := p_asso_uri,
274 ai_params := ai_params
275}
276
277// [RFC3455 4.1]
278template (present) P_Associated_Uri tr_P_Associated_Uri(template (present) P_Assoc_uri_spec_list p_assoc_uris := ?) := {
279 fieldName := P_ASSOCIATED_URI,
280 p_assoc_uris := p_assoc_uris
281}
282template (value) P_Associated_Uri ts_P_Associated_Uri(template (value) P_Assoc_uri_spec_list p_assoc_uris := {}) := {
283 fieldName := P_ASSOCIATED_URI,
284 p_assoc_uris := p_assoc_uris
285}
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200286
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200287// RFC 3262
288template (value) RAck ts_RAck(template (value) integer response_num,
289 template (value) integer seq_nr,
290 template (value) charstring method := "INVITE") := {
291 fieldName := RACK_E,
292 response_num := response_num,
293 seqNumber := seq_nr,
294 method := method
295}
296template (present) RAck tr_RAck(template (present) integer response_num := ?,
297 template (present) integer seq_nr := ?,
298 template (present) charstring method := ?) := {
299 fieldName := RACK_E,
300 response_num := response_num,
301 seqNumber := seq_nr,
302 method := method
303}
304
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200305// [20.32]
306template (value) Require ts_Require(template (value) OptionTag_List optionsTags := {}) := {
307 fieldName := REQUIRE_E,
308 optionsTags := optionsTags
309}
310template (present) Require tr_Require(template (present) OptionTag_List optionsTags := ?) := {
311 fieldName := REQUIRE_E,
312 optionsTags := optionsTags
313}
314
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200315// RFC 3262
316template (value) RSeq ts_RSeq(template (value) integer response_num) := {
317 fieldName := RSEQ_E,
318 response_num := response_num
319}
320template (present) RSeq tr_RSeq(template (present) integer response_num := ?) := {
321 fieldName := RSEQ_E,
322 response_num := response_num
323}
324
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200325// [20.35 RFC2616 14.38]
326template (value) Server ts_Server(template (value) ServerVal_List serverBody := {}) := {
327 fieldName := SERVER_E,
328 serverBody := serverBody
329}
330template (present) Server tr_Server(template (present) ServerVal_List serverBody := ?) := {
331 fieldName := SERVER_E,
332 serverBody := serverBody
333}
334
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200335// [20.37]
336template (value) Supported ts_Supported(template (value) OptionTag_List optionsTags := {}) := {
337 fieldName := SUPPORTED_E,
338 optionsTags := optionsTags
339}
340template (present) Supported tr_Supported(template (present) OptionTag_List optionsTags := ?) := {
341 fieldName := SUPPORTED_E,
342 optionsTags := optionsTags
343}
344
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200345// [20.39]
346template (value) To ts_To(template (value) Addr_Union addressField,
347 template (omit) SemicolonParam_List toParams := omit) := {
348 fieldName := TO_E,
349 addressField := addressField,
350 toParams := toParams
351}
352template (present) To tr_To(template (present) Addr_Union addressField := ?,
353 template SemicolonParam_List toParams := *) := {
354 fieldName := TO_E,
355 addressField := addressField,
356 toParams := toParams
357}
358
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200359// [20.41 RFC2616 14.43]
360template (value) UserAgent ts_UserAgent(template (value) ServerVal_List userAgentBody := {}) := {
361 fieldName := USER_AGENT_E,
362 userAgentBody := userAgentBody
363}
364template (present) UserAgent tr_UserAgent(template (present) ServerVal_List userAgentBody := ?) := {
365 fieldName := USER_AGENT_E,
366 userAgentBody := userAgentBody
367}
368
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200369
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100370template (value) SipAddr ts_SipAddr(template (value) HostPort host_port,
371 template (omit) UserInfo user_info := omit,
372 template (omit) charstring displayName := omit,
373 template (omit) SemicolonParam_List params := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100374 addr := {
375 nameAddr := {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100376 displayName := displayName,
377 addrSpec := ts_SipUrl(host_port, user_info)
Harald Welteb0d93602018-03-20 18:09:34 +0100378 }
379 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100380 params := params
381}
382template (present) SipAddr tr_SipAddr(template (present) HostPort host_port := ?,
383 template UserInfo user_info := *,
384 template charstring displayName := *,
385 template SemicolonParam_List params := *) := {
386 addr := {
387 nameAddr := {
388 displayName := displayName,
389 addrSpec := tr_SipUrl(host_port, user_info)
390 }
391 },
392 params := params
Harald Welteb0d93602018-03-20 18:09:34 +0100393}
394
395/* build a receive template from a value: substitute '*' for omit */
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200396function tr_SipUrl_from_val(template (value) SipUrl tin) return template (present) SipUrl {
397 var template (present) SipUrl ret := tin;
398
399 /* if the port number is 5060, it may be omitted */
400 if (ispresent(tin.hostPort.portField) and
401 valueof(tin.hostPort.portField) == 5060) {
402 ret.hostPort.portField := 5060 ifpresent;
403 }
404 if (not ispresent(tin.userInfo.password)) {
405 ret.userInfo.password := *;
406 }
407
408 return ret;
409}
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200410function tr_Addr_Union_from_val(template (value) Addr_Union tin) return template (present) Addr_Union {
411 var template (present) Addr_Union ret := tin;
412
413 if (not ispresent(tin.nameAddr.displayName)) {
414 ret.nameAddr.displayName := *;
415 } else if (f_str_tolower(f_sip_str_unquote(tin.nameAddr.displayName)) == "anonymous") {
416 /* if the user is Anonymous, it may be omitted */
417 ret.nameAddr.displayName := tin.nameAddr.displayName ifpresent;
418 }
419
420 ret.nameAddr.addrSpec := tr_SipUrl_from_val(tin.nameAddr.addrSpec);
421
422 return ret;
423}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200424function tr_SipAddr_from_val(template (value) SipAddr tin) return template (present) SipAddr {
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100425 var template (present) SipAddr ret := tin;
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200426
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200427 ret.addr := tr_Addr_Union_from_val(tin.addr);
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200428
429 if (not ispresent(tin.params)) {
Harald Welteb0d93602018-03-20 18:09:34 +0100430 ret.params := *;
431 }
432 return ret;
433}
434
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200435function ts_SipAddr_from_Addr_Union(template (value) Addr_Union au,
436 template (omit) SemicolonParam_List params := omit)
437return template (value) SipAddr {
438 var template (value) SipUrl addrSpec := ts_SipUrl_from_Addr_Union(au);
439 var template (omit) charstring displayName;
440
441 if (ischosen(au.nameAddr)) {
442 displayName := au.nameAddr.displayName;
443 } else { /* au.addrSpecUnion */
444 displayName := omit
445 }
446
447 return ts_SipAddr(addrSpec.hostPort,
448 addrSpec.userInfo,
449 displayName,
450 params);
451}
452
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100453template (value) HostPort ts_HostPort(template (omit) charstring host := omit,
454 template (omit) integer portField := omit) := {
455 host := host,
456 portField := portField
457}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200458
459template (present) HostPort tr_HostPort(template charstring host := *,
460 template integer portField := *) := {
461 host := host,
462 portField := portField
463}
464function f_tr_HostPort(template charstring host := *,
465 template integer portField := *)
466return template (present) HostPort {
467 return f_tr_HostPort_opt_defport(tr_HostPort(host, portField));
468}
469function f_tr_HostPort_opt_defport(template (present) HostPort hp) return template (present) HostPort {
470 var template (present) HostPort hpout := hp;
Harald Welteb0d93602018-03-20 18:09:34 +0100471 /* if the port number is 5060, it may be omitted */
472 if (isvalue(hp.portField) and valueof(hp.portField) == 5060) {
473 hpout.portField := 5060 ifpresent;
474 }
475 return hpout;
476}
477
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200478function f_tr_SipUrl_opt_defport(template (present) SipUrl url) return template (present) SipUrl {
479 var template (present) SipUrl urlout := url;
480 urlout.hostPort := f_tr_HostPort_opt_defport(url.hostPort);
481 return urlout;
482}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100483
484template (value) UserInfo ts_UserInfo(template (value) charstring userOrTelephoneSubscriber,
485 template (omit) charstring password := omit) := {
486 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
487 password := password
488}
489template (present) UserInfo tr_UserInfo(template (present) charstring userOrTelephoneSubscriber := ?,
490 template charstring password := *) := {
491 userOrTelephoneSubscriber := userOrTelephoneSubscriber,
492 password := password
493}
494
495template (value) RequestLine ts_SIP_ReqLine(Method method,
496 template (value) SipUrl uri,
Harald Welteb0d93602018-03-20 18:09:34 +0100497 charstring ver := c_SIP_VERSION) := {
498 method := method,
499 requestUri := uri,
500 sipVersion := ver
501}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100502template (present) RequestLine tr_SIP_ReqLine(template (present) Method method := ?,
503 template (present) SipUrl uri := ?,
504 template (present) charstring ver := c_SIP_VERSION) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100505 method := method,
506 requestUri := uri,
507 sipVersion := ver
508}
509
510template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := {
511 sipVersion := "SIP/2.0",
512 statusCode := status_code,
513 reasonPhrase := reason
514}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100515template (present) StatusLine tr_SIP_StatusLine(template integer status_code,
516 template charstring reason) := {
Harald Welteb0d93602018-03-20 18:09:34 +0100517 sipVersion := "SIP/2.0",
518 statusCode := status_code,
519 reasonPhrase := reason
520}
521
522
523template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := {
524 requestLine := rl,
525 msgHeader := c_SIP_msgHeader_empty,
526 messageBody := omit,
527 payload := omit
528}
529
530const Method_List c_SIP_defaultMethods := {
531 "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE",
532 "NOTIFY", "REFER", "UPDATE" };
533
534private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body)
535return template (omit) ContentType {
536 /* if user explicitly stated no content type */
537 if (istemplatekind(ct, "omit")) {
538 return omit;
539 }
540 /* if there's no body, then there's no content-type either */
541 if (istemplatekind(body, "omit")) {
542 return omit;
543 }
544 return ct;
545}
546
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200547private function f_ContentLength(template (omit) charstring body)
548return template (value) ContentLength {
549 /* rfc3261 20.14: "If no body is present in a message, then the
550 * Content-Length header field value MUST be set to zero." */
551 if (istemplatekind(body, "omit")) {
552 return ts_ContentLength(0);
553 }
554 return ts_ContentLength(lengthof(body));
555}
556
Harald Welteb0d93602018-03-20 18:09:34 +0100557template (value) ContentType ts_CT_SDP := {
558 fieldName := CONTENT_TYPE_E,
559 mediaType := "application/sdp"
560};
561
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200562template (value) Via ts_Via_from(template (value) HostPort addr,
563 template (value) charstring transport := "UDP") := {
Harald Welteb0d93602018-03-20 18:09:34 +0100564 fieldName := VIA_E,
565 viaBody := {
566 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200567 sentProtocol := { "SIP", "2.0", transport },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100568 sentBy := addr,
Harald Welteb0d93602018-03-20 18:09:34 +0100569 viaParams := omit
570 }
571 }
572}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100573template (present) Via tr_Via_from(template (present) HostPort host_port := ?,
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200574 template (present) charstring transport := ?,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100575 template SemicolonParam_List viaParams := *) := {
576 fieldName := VIA_E,
577 viaBody := {
578 {
Pau Espin Pedrol2a833372024-05-10 20:23:22 +0200579 sentProtocol := { "SIP", "2.0", ? },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100580 sentBy := host_port,
581 viaParams := viaParams
582 }
583 }
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200584}
585
586template (present) OtherAuth
587tr_OtherAuth(template (present) charstring authScheme := ?,
588 template (present) CommaParam_List authParams := ?) := {
589 authScheme := authScheme,
590 authParams := authParams
591}
592
593template (value) OtherAuth
594ts_OtherAuth(template (value) charstring authScheme,
595 template (value) CommaParam_List authParams) := {
596 authScheme := authScheme,
597 authParams := authParams
598}
599
600template (present) Challenge
601tr_Challenge_digestCln(template (present) CommaParam_List digestCln := ?) := {
602 digestCln := digestCln
603}
604
605template (value) Challenge
606ts_Challenge_digestCln(template (value) CommaParam_List digestCln) := {
607 digestCln := digestCln
608}
609
610template (present) Challenge
611tr_Challenge_otherChallenge(template (present) OtherAuth otherChallenge := ?) := {
612 otherChallenge := otherChallenge
613}
614
615template (value) Challenge
616ts_Challenge_otherChallenge(template (value) OtherAuth otherChallenge) := {
617 otherChallenge := otherChallenge
618}
619
620template (present) WwwAuthenticate
621tr_WwwAuthenticate(template (present) Challenge_list challenge := ?) := {
622 fieldName := WWW_AUTHENTICATE_E,
623 challenge := challenge
624}
625
626template (value) WwwAuthenticate
627ts_WwwAuthenticate(template (value) Challenge_list challenge) := {
628 fieldName := WWW_AUTHENTICATE_E,
629 challenge := challenge
630}
Harald Welteb0d93602018-03-20 18:09:34 +0100631
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200632// RFC3329
633template (present) Security_client
634tr_Security_client(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
635 fieldName := SECURITY_CLIENT_E,
636 sec_mechanism_list := sec_mechanism_list
637}
638template (value) Security_client
639ts_Security_client(template (value) Security_mechanism_list sec_mechanism_list) := {
640 fieldName := SECURITY_CLIENT_E,
641 sec_mechanism_list := sec_mechanism_list
642}
643
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200644template (present) Security_server
645tr_Security_server(template (present) Security_mechanism_list sec_mechanism_list := ?) := {
646 fieldName := SECURITY_SERVER_E,
647 sec_mechanism_list := sec_mechanism_list
648}
649template (value) Security_server
650ts_Security_server(template (value) Security_mechanism_list sec_mechanism_list) := {
651 fieldName := SECURITY_SERVER_E,
652 sec_mechanism_list := sec_mechanism_list
653}
654
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200655template (present) Security_mechanism
656tr_Security_mechanism(template (present) charstring name := ?,
657 template SemicolonParam_List params := *) := {
658 mechanism_name := name,
659 mechanism_params := params
660}
661template (value) Security_mechanism
662ts_Security_mechanism(template (value) charstring name,
663 template (omit) SemicolonParam_List params := omit) := {
664 mechanism_name := name,
665 mechanism_params := params
666}
667
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100668template (value) MessageHeader ts_SIP_msgHeader_empty := c_SIP_msgHeader_empty;
669template (value) MessageHeader
670ts_SIP_msgh_std(template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200671 template (value) From from_addr,
672 template (value) To to_addr,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100673 template (omit) Contact contact,
674 template (value) charstring method,
675 template (value) integer seq_nr,
676 template (value) Via via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200677 template (omit) ContentLength content_length := ts_ContentLength(0),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100678 template (omit) ContentType content_type := omit,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200679 template (omit)Authorization authorization := omit,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200680 template (omit) Allow allow := ts_Allow(c_SIP_defaultMethods),
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200681 template (omit) Expires expires := omit,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +0200682 template (omit) P_Associated_Uri p_associated_uri := omit,
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200683 template (omit) RAck rack := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200684 template (omit) Require require := omit,
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200685 template (omit) RSeq rseq := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200686 template (omit) Security_client security_client := omit,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200687 template (omit) Security_server security_server := omit,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200688 template (omit) Server server := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200689 template (omit) Supported supported := omit,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200690 template (omit) UserAgent userAgent := ts_UserAgent({ "osmo-ttcn3-hacks/0.23" }),
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200691 template (omit) WwwAuthenticate wwwAuthenticate := omit
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100692 ) modifies ts_SIP_msgHeader_empty := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200693 allow := allow,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200694 authorization := authorization,
Harald Welteb0d93602018-03-20 18:09:34 +0100695 callId := {
696 fieldName := CALL_ID_E,
697 callid := call_id
698 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100699 contact := contact,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200700 contentLength := content_length,
Harald Welteb0d93602018-03-20 18:09:34 +0100701 contentType := content_type,
702 cSeq := {
703 fieldName := CSEQ_E,
704 seqNumber := seq_nr,
705 method := method
706 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100707 expires := expires,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200708 fromField := from_addr,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +0200709 p_associated_uri := p_associated_uri,
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200710 rack := rack,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200711 require := require,
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200712 rseq := rseq,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200713 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200714 security_server := security_server,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200715 server := server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200716 supported := supported,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200717 toField := to_addr,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200718 userAgent := userAgent,
Pau Espin Pedrol89d8c952024-05-10 20:28:24 +0200719 via := via,
720 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100721}
722
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100723template (present) MessageHeader
724tr_SIP_msgh_std(template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200725 template From from_addr,
726 template To to_addr,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100727 template Contact contact,
728 template (present) Via via := tr_Via_from(?),
729 template charstring method,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100730 template integer seq_nr := ?,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200731 template ContentLength content_length := *,
732 template ContentType content_type := *,
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200733 template Allow allow := *,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200734 template Authorization authorization := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200735 template Expires expires := *,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +0200736 template P_Associated_Uri p_associated_uri := *,
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200737 template RAck rack := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200738 template Require require := *,
Pau Espin Pedrolce370df2024-06-18 13:45:53 +0200739 template RSeq rseq := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200740 template Security_client security_client := *,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200741 template Security_server security_server := *,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200742 template Server server := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200743 template Supported supported := *,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200744 template UserAgent userAgent := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200745 template WwwAuthenticate wwwAuthenticate := *
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100746 ) modifies t_SIP_msgHeader_any := {
Pau Espin Pedrolcb3a15b2024-05-13 16:25:11 +0200747 allow := allow,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200748 authorization := authorization,
Harald Welteb0d93602018-03-20 18:09:34 +0100749 callId := {
750 fieldName := CALL_ID_E,
751 callid := call_id
752 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100753 contact := contact,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200754 contentLength := content_length,
Harald Welteb0d93602018-03-20 18:09:34 +0100755 contentType := content_type,
756 cSeq := {
757 fieldName := CSEQ_E,
758 seqNumber := seq_nr,
759 method := method
760 },
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100761 expires := expires,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200762 fromField := from_addr,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +0200763 p_associated_uri := p_associated_uri,
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200764 rack := rack,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200765 require := require,
Pau Espin Pedrolce370df2024-06-18 13:45:53 +0200766 rseq := rseq,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200767 security_client := security_client,
Pau Espin Pedrol7f411562024-05-13 13:58:41 +0200768 security_server := security_server,
Pau Espin Pedrol52cc2e52024-05-13 17:50:20 +0200769 server := server,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200770 supported := supported,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200771 toField := to_addr,
Pau Espin Pedrol13c50ac2024-05-13 17:48:09 +0200772 userAgent := userAgent,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200773 via := via,
774 wwwAuthenticate := wwwAuthenticate
Harald Welteb0d93602018-03-20 18:09:34 +0100775}
776
777
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100778template (value) PDU_SIP_Request
779ts_SIP_REGISTER(template (value) SipUrl sip_url_host_port,
780 template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200781 template (value) From from_addr,
782 template (value) To to_addr,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100783 template (value) Via via,
784 integer seq_nr,
785 template (omit) Contact contact,
786 template (omit) Expires expires,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200787 template (omit) Authorization authorization := omit,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200788 template (omit) Require require := omit,
789 template (omit) Security_client security_client := omit,
790 template (omit) Supported supported := omit,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100791 template (omit) charstring body := omit) := {
792 requestLine := ts_SIP_ReqLine(REGISTER_E, sip_url_host_port),
793 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
794 "REGISTER", seq_nr, via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200795 content_length := f_ContentLength(body),
796 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +0200797 authorization := authorization,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200798 expires := expires,
799 require := require,
800 security_client := security_client,
801 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100802 messageBody := body,
803 payload := omit
804}
805template (present) PDU_SIP_Request
806tr_SIP_REGISTER(template (present) SipUrl sip_url_host_port := ?,
807 template (present) CallidString call_id := ?,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200808 template (present) From from_addr := ?,
809 template (present) To to_addr := ?,
Pau Espin Pedrol0dd3f262024-04-25 17:04:43 +0200810 template (present) Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100811 template integer seq_nr := *,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200812 template Authorization authorization := *,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100813 template Contact contact := *,
814 template Expires expires := *,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200815 template Require require := *,
816 template Security_client security_client := *,
817 template Supported supported := *,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100818 template charstring body := *) := {
819 requestLine := tr_SIP_ReqLine(REGISTER_E, sip_url_host_port),
820 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200821 via, "REGISTER", seq_nr,
Pau Espin Pedrola674d612024-05-14 19:56:33 +0200822 authorization := authorization,
Pau Espin Pedrol73f6a312024-05-10 20:30:16 +0200823 expires := expires,
824 require := require,
825 security_client := security_client,
826 supported := supported),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100827 messageBody := body,
828 payload := omit
829}
830
831template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200832ts_SIP_INVITE(template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200833 template (value) From from_addr,
834 template (value) To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200835 template (value) Via via,
836 template (value) Contact contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100837 integer seq_nr,
Pau Espin Pedrolce370df2024-06-18 13:45:53 +0200838 template (omit) Supported supported := omit,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100839 template (omit) charstring body := omit) := {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200840 requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addressField.nameAddr.addrSpec),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200841 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100842 "INVITE", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200843 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200844 content_length := f_ContentLength(body),
Pau Espin Pedrolce370df2024-06-18 13:45:53 +0200845 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
846 supported := supported),
Harald Welteb0d93602018-03-20 18:09:34 +0100847 messageBody := body,
848 payload := omit
849}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100850template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200851tr_SIP_INVITE(template (present) SipUrl uri,
852 template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200853 template From from_addr,
854 template To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200855 template Via via := tr_Via_from(f_tr_HostPort_opt_defport(?)),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100856 template integer seq_nr,
857 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200858 requestLine := tr_SIP_ReqLine(INVITE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100859 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200860 via, "INVITE", seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100861 messageBody := body,
862 payload := omit
863}
864
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100865template (value) PDU_SIP_Request
866ts_SIP_BYE(CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200867 template (value) From from_addr,
868 template (value) To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200869 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100870 integer seq_nr,
871 template (omit) charstring body) := {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200872 requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addressField.nameAddr.addrSpec),
Harald Welteb0d93602018-03-20 18:09:34 +0100873 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200874 via,
875 content_length := f_ContentLength(body),
876 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100877 messageBody := body,
878 payload := omit
879}
880
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100881template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200882tr_SIP_BYE(template (present) SipUrl uri,
883 template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200884 template From from_addr,
885 template To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200886 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100887 template integer seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200888 template charstring body := *) := {
889 requestLine := tr_SIP_ReqLine(BYE_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100890 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200891 via, "BYE", seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100892 messageBody := body,
893 payload := omit
894}
895
896
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100897template (value) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200898ts_SIP_ACK(template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200899 template (value) From from_addr,
900 template (value) To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200901 template (value) Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100902 integer seq_nr,
903 template (omit) charstring body) := {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200904 requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addressField.nameAddr.addrSpec),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100905 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200906 ts_Contact({ ts_ContactAddress(from_addr.addressField, from_addr.fromParams) }),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100907 "ACK", seq_nr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200908 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200909 content_length := f_ContentLength(body),
910 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Harald Welteb0d93602018-03-20 18:09:34 +0100911 messageBody := body,
912 payload := omit
913}
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100914template (present) PDU_SIP_Request
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200915tr_SIP_ACK(template (present) SipUrl uri,
916 template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200917 template From from_addr,
918 template To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200919 template Via via,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100920 template integer seq_nr,
921 template charstring body) := {
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200922 requestLine := tr_SIP_ReqLine(ACK_E, uri),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +0100923 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +0200924 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200925 "ACK", seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +0100926 messageBody := body,
927 payload := omit
928}
929
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200930template (present) PDU_SIP_Request
931tr_SIP_CANCEL(template (present) SipUrl uri,
932 template (present) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +0200933 template (present) From from_addr,
934 template (present) To to_addr,
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200935 template (present) Via via,
936 template (present) integer seq_nr,
937 template charstring body := *) := {
938 requestLine := tr_SIP_ReqLine(CANCEL_E, uri),
939 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
940 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +0200941 "CANCEL", seq_nr),
Pau Espin Pedrol32167d82024-04-10 13:14:51 +0200942 messageBody := body,
943 payload := omit
944}
945
Pau Espin Pedrolce370df2024-06-18 13:45:53 +0200946template (value) PDU_SIP_Request
947ts_SIP_PRACK(template (value) SipUrl uri,
948 template (value) CallidString call_id,
949 template (value) From from_addr,
950 template (value) To to_addr,
951 template (value) Via via,
952 integer seq_nr,
953 template (value) RAck rack,
954 template (omit) charstring body := omit) := {
955 requestLine := ts_SIP_ReqLine(PRACK_E, uri),
956 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit,
957 "PRACK", seq_nr,
958 via,
959 content_length := f_ContentLength(body),
960 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
961 rack := rack),
962 messageBody := body,
963 payload := omit
964}
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +0200965template (present) PDU_SIP_Request
966tr_SIP_PRACK(template (present) SipUrl uri,
967 template CallidString call_id,
968 template From from_addr,
969 template To to_addr,
970 template Via via,
971 template integer seq_nr,
972 template RAck rack := tr_RAck(?, ?, ?),
973 template charstring body := *) := {
974 requestLine := tr_SIP_ReqLine(PRACK_E, uri),
975 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
976 via,
977 "PRACK", seq_nr,
978 rack := rack),
979 messageBody := body,
980 payload := omit
981}
982
Pau Espin Pedrolce370df2024-06-18 13:45:53 +0200983template (value) PDU_SIP_Request
984ts_SIP_UPDATE(template (value) SipUrl uri,
985 template (value) CallidString call_id,
986 template (value) From from_addr,
987 template (value) To to_addr,
988 template (value) Via via,
989 integer seq_nr,
990 template (omit) Contact contact,
991 template (value) Require require := ts_Require({"sec-agree", "precondition"}),
992 template (value) charstring body) := {
993 requestLine := ts_SIP_ReqLine(UPDATE_E, uri),
994 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact,
995 "UPDATE", seq_nr,
996 via,
997 require := require),
998 messageBody := body,
999 payload := omit
1000}
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +02001001template (present) PDU_SIP_Request
1002tr_SIP_UPDATE(template (present) SipUrl uri,
1003 template CallidString call_id,
1004 template From from_addr,
1005 template To to_addr,
1006 template Via via,
1007 template integer seq_nr,
1008 template Require require := *,
1009 template charstring body) := {
1010 requestLine := tr_SIP_ReqLine(UPDATE_E, uri),
1011 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
1012 via,
1013 "UPDATE", seq_nr,
1014 require := require),
1015 messageBody := body,
1016 payload := omit
1017}
1018
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +01001019template (value) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001020ts_SIP_Response(template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001021 template (value) From from_addr,
1022 template (value) To to_addr,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +01001023 charstring method,
1024 integer status_code,
1025 integer seq_nr,
1026 charstring reason,
1027 Via via,
Pau Espin Pedrola674d612024-05-14 19:56:33 +02001028 template (omit) Allow allow := omit,
Pau Espin Pedrol586eec52024-06-04 19:07:33 +02001029 template (omit) Contact contact := omit,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +02001030 template (omit) P_Associated_Uri p_associated_uri := omit,
Pau Espin Pedrola674d612024-05-14 19:56:33 +02001031 template (omit) Require require := omit,
1032 template (omit) Server server := omit,
1033 template (omit) Supported supported := omit,
1034 template (omit) UserAgent userAgent := omit,
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +01001035 template (omit) charstring body := omit) := {
Harald Welteb0d93602018-03-20 18:09:34 +01001036 statusLine := ts_SIP_StatusLine(status_code, reason),
Pau Espin Pedrol586eec52024-06-04 19:07:33 +02001037 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, contact, method, seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +02001038 via,
1039 content_length := f_ContentLength(body),
Pau Espin Pedrola674d612024-05-14 19:56:33 +02001040 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
1041 allow := allow,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +02001042 p_associated_uri := p_associated_uri,
Pau Espin Pedrola674d612024-05-14 19:56:33 +02001043 require := require,
1044 server := server,
1045 supported := supported,
1046 userAgent := userAgent),
Harald Welteb0d93602018-03-20 18:09:34 +01001047 messageBody := body,
1048 payload := omit
1049}
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +02001050/* 100 Trying */
1051template (value) PDU_SIP_Response
1052ts_SIP_Response_Trying(
1053 template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001054 template (value) From from_addr,
1055 template (value) To to_addr,
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +02001056 Via via,
1057 integer seq_nr,
1058 charstring method := "INVITE",
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +02001059 template (omit) Allow allow := omit,
1060 template (omit) Server server := omit,
1061 template (omit) UserAgent userAgent := omit,
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +02001062 template (omit) charstring body := omit) := {
1063 statusLine := ts_SIP_StatusLine(100, "Trying"),
1064 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +02001065 via,
1066 content_length := f_ContentLength(body),
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +02001067 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
1068 allow := allow,
1069 server := server,
1070 userAgent := userAgent),
Pau Espin Pedrol1b5f7ba2024-05-13 16:38:38 +02001071 messageBody := body,
1072 payload := omit
1073}
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001074/* 180 Ringing */
1075template (value) PDU_SIP_Response
1076ts_SIP_Response_Ringing(
1077 template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001078 template (value) From from_addr,
1079 template (value) To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001080 Via via,
1081 integer seq_nr,
1082 charstring method := "INVITE",
1083 template (omit) charstring body := omit) := {
1084 statusLine := ts_SIP_StatusLine(180, "Ringing"),
1085 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +02001086 via,
1087 content_length := f_ContentLength(body),
1088 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body)),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001089 messageBody := body,
1090 payload := omit
1091}
1092
Pau Espin Pedrolfaf21be2024-06-12 16:42:00 +02001093/* 183 Session Progress */
1094template (value) PDU_SIP_Response
1095ts_SIP_Response_SessionProgress(
1096 template (value) CallidString call_id,
1097 template (value) From from_addr,
1098 template (value) To to_addr,
1099 Via via,
1100 integer seq_nr,
1101 charstring method := "INVITE",
1102 template (omit) Require require := ts_Require({"100rel", "precondition"}),
1103 template (omit) RSeq rseq := ts_RSeq(1),
1104 template (omit) charstring body := omit) := {
1105 statusLine := ts_SIP_StatusLine(183, "Session Progress"),
1106 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
1107 via,
1108 content_length := f_ContentLength(body),
1109 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
1110 require := require,
1111 rseq := rseq),
1112 messageBody := body,
1113 payload := omit
1114}
1115
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +02001116/* 401 Unauthorized */
1117template (value) PDU_SIP_Response
1118ts_SIP_Response_Unauthorized(
1119 template (value) CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001120 template (value) From from_addr,
1121 template (value) To to_addr,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +02001122 Via via,
1123 template (value) WwwAuthenticate wwwAuthenticate,
1124 integer seq_nr,
1125 charstring method := "REGISTER",
1126 template (omit) Allow allow := omit,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +02001127 template (omit) P_Associated_Uri p_associated_uri := omit,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +02001128 template (omit) Security_server security_server := omit,
1129 template (omit) Server server := omit,
1130 template (omit) Supported supported := omit,
1131 template (omit) UserAgent userAgent := omit,
1132 template (omit) charstring body := omit) := {
1133 statusLine := ts_SIP_StatusLine(401, "Unauthorized"),
1134 msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr,
1135 via,
1136 content_length := f_ContentLength(body),
1137 content_type := f_ContentTypeOrOmit(ts_CT_SDP, body),
1138 allow := allow,
Pau Espin Pedrol4e6672c2024-05-22 17:03:53 +02001139 p_associated_uri := p_associated_uri,
Pau Espin Pedrola2812ec2024-05-10 20:30:44 +02001140 security_server := security_server,
1141 server := server,
1142 supported := supported,
1143 userAgent := userAgent,
1144 wwwAuthenticate := wwwAuthenticate),
1145 messageBody := body,
1146 payload := omit
1147}
1148
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +01001149template (present) PDU_SIP_Response
1150tr_SIP_Response(template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001151 template From from_addr,
1152 template To to_addr,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001153 template (present) Via via := tr_Via_from(?),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +01001154 template Contact contact,
1155 template charstring method,
1156 template integer status_code,
1157 template integer seq_nr := ?,
1158 template charstring reason := ?,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001159 template charstring body := *) := {
Harald Welteb0d93602018-03-20 18:09:34 +01001160 statusLine := tr_SIP_StatusLine(status_code, reason),
Pau Espin Pedrolfb34d862024-03-28 20:21:38 +01001161 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001162 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +02001163 method, seq_nr),
Harald Welteb0d93602018-03-20 18:09:34 +01001164 messageBody := body,
1165 payload := omit
1166}
1167
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001168/* Expect during first REGISTER/INVITE/... when authorization is required: */
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +01001169template (present) PDU_SIP_Response
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001170tr_SIP_Response_Unauthorized(
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +01001171 template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001172 template From from_addr,
1173 template To to_addr,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +01001174 template (present) Via via := tr_Via_from(?),
1175 template Contact contact := *,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001176 template (present) WwwAuthenticate wwwAuthenticate := ?,
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +01001177 template integer seq_nr := ?,
1178 template charstring method := "REGISTER",
1179 template integer status_code := 401,
1180 template charstring reason := "Unauthorized",
1181 template charstring body := *) := {
1182 statusLine := tr_SIP_StatusLine(status_code, reason),
1183 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
1184 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +02001185 method, seq_nr,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001186 wwwAuthenticate := wwwAuthenticate),
Pau Espin Pedrol37ee0ed2024-03-28 21:17:12 +01001187 messageBody := body,
1188 payload := omit
1189}
Harald Welteb0d93602018-03-20 18:09:34 +01001190
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001191/* 100 Trying */
1192template (present) PDU_SIP_Response
1193tr_SIP_Response_Trying(
1194 template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001195 template From from_addr,
1196 template To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001197 template (present) Via via := tr_Via_from(?),
1198 template integer seq_nr := ?,
1199 template charstring method := "INVITE",
1200 template integer status_code := 100,
1201 template charstring reason := "Trying",
1202 template charstring body := *) := {
1203 statusLine := tr_SIP_StatusLine(status_code, reason),
1204 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit,
1205 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +02001206 method, seq_nr),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001207 messageBody := body,
1208 payload := omit
1209}
1210
1211/* 180 Ringing */
1212template (present) PDU_SIP_Response
1213tr_SIP_Response_Ringing(
1214 template CallidString call_id,
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001215 template From from_addr,
1216 template To to_addr,
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001217 template (present) Via via := tr_Via_from(?),
1218 template integer seq_nr := ?,
1219 template charstring method := "INVITE",
1220 template integer status_code := 180,
1221 template charstring reason := "Ringing",
1222 template charstring body := *) := {
1223 statusLine := tr_SIP_StatusLine(status_code, reason),
1224 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
1225 via,
Pau Espin Pedrol5c36a652024-05-14 16:05:59 +02001226 method, seq_nr),
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001227 messageBody := body,
1228 payload := omit
1229}
1230
Pau Espin Pedrolce370df2024-06-18 13:45:53 +02001231/* 183 Session Progress */
1232template (present) PDU_SIP_Response
1233tr_SIP_Response_SessionProgress(
1234 template (present) CallidString call_id,
1235 template (present) From from_addr,
1236 template (present) To to_addr,
1237 template (present) Via via,
1238 template (present) integer seq_nr := ?,
1239 template (present) charstring method := "INVITE",
1240 template Require require := *,
1241 template RSeq rseq := *,
1242 template (omit) charstring body := omit) := {
1243 statusLine := tr_SIP_StatusLine(183, "Session Progress"),
1244 msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *,
1245 via,
1246 method, seq_nr,
1247 require := require,
1248 rseq := rseq),
1249 messageBody := body,
1250 payload := omit
1251}
1252
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001253/****************
1254 * FUNCTIONS:
1255 ****************/
1256
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001257function f_sip_param_find(GenericParam_List li,
1258 template (present) charstring id := ?)
1259return template (omit) GenericParam {
1260 var integer i;
1261
1262 for (i := 0; i < lengthof(li); i := i + 1) {
1263 if (not ispresent(li[i])) {
1264 continue;
1265 }
1266 if (match(li[i].id, id)) {
1267 return li[i];
1268 }
1269 }
1270 return omit;
1271}
1272
1273function f_sip_param_find_or_fail(GenericParam_List li,
1274 template (present) charstring id := ?)
1275return GenericParam {
1276 var template (omit) GenericParam parameter;
1277 parameter := f_sip_param_find(li, id);
1278 if (istemplatekind(parameter, "omit")) {
1279 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1280 log2str("Param ", id, " not found in ", li));
1281 }
1282 return valueof(parameter);
1283}
1284
1285function f_sip_param_get_value(GenericParam_List li,
1286 template (present) charstring id := ?)
1287return template (omit) charstring {
1288 var template (omit) GenericParam parameter;
1289 parameter := f_sip_param_find(li, id);
1290 if (istemplatekind(parameter, "omit")) {
1291 return omit;
1292 }
1293 return parameter.paramValue;
1294}
1295
1296function f_sip_param_get_value_or_fail(GenericParam_List li,
1297 template (present) charstring id := ?)
1298return template (omit) charstring {
1299 var GenericParam parameter;
1300 parameter := f_sip_param_find_or_fail(li, id);
1301 return parameter.paramValue;
1302}
1303
1304function f_sip_param_get_value_present_or_fail(GenericParam_List li,
1305 template (present) charstring id := ?)
1306return charstring {
1307 var GenericParam parameter;
1308 parameter := f_sip_param_find_or_fail(li, id);
1309 if (not ispresent(parameter.paramValue)) {
1310 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1311 log2str("Param ", id, " value not present in ", li));
1312 }
1313 return parameter.paramValue;
1314}
1315
1316function f_sip_param_match_value(GenericParam_List li,
1317 template (present) charstring id := ?,
1318 template charstring exp_paramValue := *)
1319return boolean {
1320 var template (omit) charstring val;
1321 val := f_sip_param_get_value_or_fail(li, id);
1322 if (istemplatekind(val, "omit")) {
1323 return istemplatekind(val, "omit") or istemplatekind(val, "*");
1324 }
1325 return match(valueof(val), exp_paramValue);
1326}
1327
1328function f_sip_param_match_value_or_fail(GenericParam_List li,
1329 template (present) charstring id := ?,
1330 template charstring exp_paramValue := *)
1331{
1332 var template (omit) charstring val := f_sip_param_get_value_or_fail(li, id);
1333 if (istemplatekind(val, "omit")) {
1334 if (istemplatekind(val, "omit") or istemplatekind(val, "*")) {
1335 return;
1336 } else {
1337 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1338 log2str("Param ", id, " match failed: val ", val,
1339 " vs exp ", exp_paramValue));
1340 }
1341 }
1342 if (not match(valueof(val), exp_paramValue)) {
1343 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1344 log2str("Param ", id, " match failed: val ", val,
1345 " vs exp ", exp_paramValue));
1346 }
1347}
1348
1349function f_sip_param_remove(template (omit) GenericParam_List li_tpl, charstring id)
1350return GenericParam_List {
1351 var integer i;
1352 var GenericParam_List li;
1353 var GenericParam_List new_li := {};
1354
1355 if (istemplatekind(li_tpl, "omit")) {
1356 return {};
1357 }
1358
1359 li := valueof(li_tpl);
1360 for (i := 0; i < lengthof(li); i := i + 1) {
1361 if (not ispresent(li[i]) or
1362 not match(li[i].id, id)) {
1363 new_li := new_li & {li[i]};
1364 }
1365 }
1366 return new_li;
1367}
1368
1369function f_sip_param_set(template (omit) GenericParam_List li_tpl, charstring id, charstring val)
1370return GenericParam_List {
1371 var integer i;
1372 var GenericParam_List li;
1373 var GenericParam_List new_li := {};
1374 var boolean found := false;
1375
1376 if (istemplatekind(li_tpl, "omit")) {
1377 return { valueof(ts_Param(id, val)) };
1378 }
1379
1380 li := valueof(li_tpl);
1381 for (i := 0; i < lengthof(li); i := i + 1) {
1382 if (not ispresent(li[i]) or
1383 not match(li[i].id, id)) {
1384 new_li := new_li & {li[i]};
1385 continue;
1386 }
1387 new_li := new_li & { valueof(ts_Param(li[i].id, val)) };
1388 found := true;
1389 }
1390
1391 if (not found) {
1392 new_li := new_li & { valueof(ts_Param(id, val)) };
1393 }
1394 return new_li;
1395}
1396
1397/* Make sure string is quoted. */
1398function f_sip_str_quote(template (value) charstring val) return charstring {
1399 var charstring str := valueof(val);
1400 if (lengthof(str) == 0) {
1401 return "";
1402 }
1403
1404 if (str[0] != "\"") {
1405 return "\"" & str & "\"";
1406 }
1407 return str;
1408}
1409
1410/* Make sure string is unquoted.
1411 * Similar to unq() in RFC 2617 */
1412function f_sip_str_unquote(template (value) charstring val) return charstring {
1413 var charstring str := valueof(val);
1414 var integer len := lengthof(str);
1415
1416 if (len <= 1) {
1417 return str;
1418 }
1419
1420 if (str[0] == "\"" and str[len - 1] == "\"") {
1421 return substr(str, 1, len - 2);
1422 }
1423 return str;
1424}
1425
1426/* RFC 2617 3.2.2.2 A1 */
1427function f_sip_digest_A1(charstring user, charstring realm, charstring password) return charstring {
1428
1429 /* RFC 2617 3.2.2.2 A1 */
1430 var charstring A1 := f_sip_str_unquote(user) & ":" &
1431 f_sip_str_unquote(realm) & ":" &
1432 password;
1433 var charstring digestA1 := f_str_tolower(f_calculateMD5(A1));
Pau Espin Pedrol80b981a2024-06-04 18:37:22 +02001434 log("A1: md5(", A1, ") = ", digestA1);
1435 return digestA1;
1436}
1437
1438/* RFC 3310: Same as f_sip_digest_A1(), but using an octet buffer as password (AKAv1-MD5, pwd=RES) */
1439function f_sip_digest_A1_octpwd(charstring user, charstring realm, octetstring password) return charstring {
1440 var charstring A1pre := f_sip_str_unquote(user) & ":" &
1441 f_sip_str_unquote(realm) & ":";
1442 var octetstring A1 := char2oct(A1pre) & password;
1443 var charstring digestA1 := f_str_tolower(oct2str(f_calculateMD5_oct(A1)));
1444 log("A1-octpwd: md5(", A1, ") = ", digestA1);
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001445 return digestA1;
1446}
1447
1448/* RFC 2617 3.2.2.2 A2 */
1449function f_sip_digest_A2(charstring method, charstring uri) return charstring {
1450
1451 var charstring A2 := method & ":" & uri
1452 var charstring digestA2 := f_str_tolower(f_calculateMD5(A2));
Pau Espin Pedrol80b981a2024-06-04 18:37:22 +02001453 log("A2: md5(", A2, ") = ", digestA2);
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001454 return digestA2;
1455}
1456
1457/* RFC 2617 3.2.2.1 Request-Digest */
1458function f_sip_digest_RequestDigest(charstring digestA1, charstring nonce,
1459 charstring nc, charstring cnonce,
1460 charstring qop, charstring digestA2) return charstring {
1461 var charstring digest_data := f_sip_str_unquote(nonce) & ":" &
1462 nc & ":" &
1463 cnonce & ":" &
1464 f_sip_str_unquote(qop) & ":" &
1465 digestA2;
1466 var charstring req_digest := f_sip_digest_KD(digestA1, digest_data);
Pau Espin Pedrol80b981a2024-06-04 18:37:22 +02001467 log("Request-Digest: md5(\"" & digestA1 & ":" & digest_data & "\") = " & "\"" & req_digest & "\"");
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001468 return req_digest;
1469}
1470
1471/* RFC 2617 3.2.1 The WWW-Authenticate Response Header
1472 * KD(secret, data) = H(concat(secret, ":", data))
1473 */
1474function f_sip_digest_KD(charstring secret, charstring data) return charstring {
1475 return f_str_tolower(f_calculateMD5(secret & ":" & data));
1476}
1477
1478/* Digest Auth: RFC 2617 */
Pau Espin Pedrol80b981a2024-06-04 18:37:22 +02001479function f_sip_digest_gen_Authorization_Response_MD5(charstring user, charstring realm, charstring password,
1480 charstring method, charstring uri, charstring qop,
1481 charstring nonce, charstring cnonce, charstring nc)
1482return charstring {
1483 /* RFC 2617 3.2.2.2 A1 */
1484 var charstring digestA1 := f_sip_digest_A1(user, realm, password);
1485
1486 /* RFC 2617 3.2.2.3 A2 */
1487 var charstring digestA2 := f_sip_digest_A2(method, uri);
1488
1489 /* RFC 2617 3.2.2.1 Request-Digest */
1490 var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
1491 nc, cnonce,
1492 qop, digestA2);
1493 return req_digest;
1494}
1495
1496/* Digest Auth: RFC 2617 */
1497function f_sip_digest_gen_Authorization_Response_AKAv1MD5(charstring user, charstring realm, octetstring password,
1498 charstring method, charstring uri, charstring qop,
1499 charstring nonce, charstring cnonce, charstring nc)
1500return charstring {
1501 /* RFC 2617 3.2.2.2 A1 */
1502 var charstring digestA1 := f_sip_digest_A1_octpwd(user, realm, password);
1503 /* RFC 2617 3.2.2.3 A2 */
1504 var charstring digestA2 := f_sip_digest_A2(method, uri);
1505
1506 /* RFC 2617 3.2.2.1 Request-Digest */
1507 var charstring req_digest := f_sip_digest_RequestDigest(digestA1, nonce,
1508 nc, cnonce,
1509 qop, digestA2);
1510 return req_digest;
1511}
1512
1513function f_sip_digest_gen_Authorization_MD5(WwwAuthenticate www_authenticate,
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001514 charstring user, charstring password,
1515 charstring method, charstring uri,
1516 charstring cnonce := "0a4f113b", integer nc_int := 1) return Authorization {
1517 var CommaParam_List digestCln;
1518 var template (value) Authorization authorization;
1519 var template (value) Credentials cred;
1520 var template (omit) GenericParam rx_param;
1521
1522 digestCln := www_authenticate.challenge[0].digestCln;
1523
1524 var charstring algorithm;
1525 rx_param := f_sip_param_find(digestCln, "algorithm");
1526 if (istemplatekind(rx_param, "omit")) {
1527 /* Assume MD5 if not set */
1528 algorithm := "MD5"
1529 } else {
1530 algorithm := valueof(rx_param.paramValue);
1531 if (f_strstr(algorithm, "MD5") == -1) {
1532 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1533 log2str("Unexpected algorithm: ", algorithm));
1534 }
1535 }
1536
1537 var charstring realm := f_sip_param_get_value_present_or_fail(digestCln, "realm");
1538 var charstring nonce := f_sip_param_get_value_present_or_fail(digestCln, "nonce");
1539 var charstring opaque := f_sip_param_get_value_present_or_fail(digestCln, "opaque");
1540 var charstring qop := f_sip_param_get_value_present_or_fail(digestCln, "qop");
1541
1542 if (f_strstr(qop, "auth") == -1) {
1543 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected qop: ", qop));
1544 }
1545 var charstring selected_qop := "auth";
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001546 var charstring nc := f_str_tolower(hex2str(int2hex(nc_int, 8)));
Pau Espin Pedrol80b981a2024-06-04 18:37:22 +02001547
1548 var charstring req_digest;
1549 req_digest :=
1550 f_sip_digest_gen_Authorization_Response_MD5(user, realm, password,
1551 method, uri, selected_qop,
1552 nonce, cnonce, nc);
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001553
1554 cred := ts_Credentials_DigestResponseMD5(user, realm, nonce,
1555 uri, req_digest,
1556 opaque, algorithm, selected_qop, cnonce, nc);
1557
1558 authorization := ts_Authorization(cred);
1559 return valueof(authorization);
1560}
1561
Pau Espin Pedrol80b981a2024-06-04 18:37:22 +02001562/* RFC 3310: Same as f_sip_digest_validate_Authorization_MD5(), but using an octet buffer as password (AKAv1-MD5, pwd=RES) */
1563function f_sip_digest_validate_Authorization_AKAv1MD5(Authorization authorization, charstring method, octetstring password) {
1564 var CommaParam_List auth_pars := authorization.body.digestResponse;
1565 var template (omit) GenericParam rx_param;
1566
1567 rx_param := f_sip_param_find(auth_pars, "algorithm");
1568 if (istemplatekind(rx_param, "omit")) {
1569 /* Assume MD5 if not set */
1570 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Algorithm param not present");
1571 } else {
1572 var charstring algorithm := valueof(rx_param.paramValue);
1573 if (f_strstr(algorithm, "AKAv1-MD5") == -1) {
1574 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1575 log2str("Unexpected algorithm: ", algorithm));
1576 }
1577 }
1578
1579 var charstring user := f_sip_param_get_value_present_or_fail(auth_pars, "username");
1580 var charstring realm := f_sip_param_get_value_present_or_fail(auth_pars, "realm");
1581 var charstring uri := f_sip_param_get_value_present_or_fail(auth_pars, "uri");
1582 var charstring nonce := f_sip_param_get_value_present_or_fail(auth_pars, "nonce");
1583 var charstring qop := f_sip_param_get_value_present_or_fail(auth_pars, "qop");
1584 var charstring response := f_sip_param_get_value_present_or_fail(auth_pars, "response");
1585 var charstring cnonce := f_sip_param_get_value_present_or_fail(auth_pars, "cnonce");
1586 var charstring nc := f_sip_param_get_value_present_or_fail(auth_pars, "nc");
1587
1588 if (f_strstr(qop, "auth") == -1) {
1589 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected qop: ", qop));
1590 }
1591
1592 var charstring exp_response :=
1593 f_sip_digest_gen_Authorization_Response_AKAv1MD5(f_sip_str_unquote(user),
1594 f_sip_str_unquote(realm),
1595 password,
1596 method,
1597 f_sip_str_unquote(uri),
1598 qop,
1599 f_sip_str_unquote(nonce),
1600 f_sip_str_unquote(cnonce),
1601 nc);
1602
1603 response := f_sip_str_unquote(response);
1604 if (response != exp_response) {
1605 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
1606 log2str("Wrong digest response: ", response,
1607 " vs exp: ", exp_response, ". Params: ", auth_pars));
1608 }
1609}
1610
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001611/* RFC 2617 3.5 Example */
1612function f_sip_digest_selftest() {
1613/*
1614The following example assumes that an access-protected document is
1615being requested from the server via a GET request. The URI of the
1616document is "http://www.nowhere.org/dir/index.html". Both client and
1617server know that the username for this document is "Mufasa", and the
1618password is "Circle Of Life" (with one space between each of the
1619three words).
1620
1621HTTP/1.1 401 Unauthorized
1622WWW-Authenticate: Digest
1623 realm="testrealm@host.com",
1624 qop="auth,auth-int",
1625 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1626 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1627
1628Authorization: Digest username="Mufasa",
1629 realm="testrealm@host.com",
1630 nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
1631 uri="/dir/index.html",
1632 qop=auth,
1633 nc=00000001,
1634 cnonce="0a4f113b",
1635 response="6629fae49393a05397450978507c4ef1",
1636 opaque="5ccc069c403ebaf9f0171e9517f40e41"
1637*/
1638 var template (value) CommaParam_List digestCln := {
1639 ts_Param("realm", f_sip_str_quote("testrealm@host.com")),
1640 ts_Param("qop", f_sip_str_quote("auth,auth-int")),
1641 ts_Param("nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093")),
1642 ts_Param("opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"))
1643 };
1644 var template (value) WwwAuthenticate www_authenticate :=
1645 ts_WwwAuthenticate( { ts_Challenge_digestCln(digestCln) } )
1646
1647 var Authorization authorization :=
Pau Espin Pedrol80b981a2024-06-04 18:37:22 +02001648 f_sip_digest_gen_Authorization_MD5(valueof(www_authenticate),
1649 "Mufasa",
1650 "Circle Of Life",
1651 "GET",
1652 "/dir/index.html",
1653 cnonce := "0a4f113b",
1654 nc_int := 1);
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001655
1656 var CommaParam_List digestResp := authorization.body.digestResponse;
1657 f_sip_param_match_value_or_fail(digestResp, "realm", f_sip_str_quote("testrealm@host.com"));
1658 f_sip_param_match_value_or_fail(digestResp, "nonce", f_sip_str_quote("dcd98b7102dd2f0e8b11d0f600bfb0c093"));
1659 f_sip_param_match_value_or_fail(digestResp, "uri", f_sip_str_quote("/dir/index.html"));
1660 f_sip_param_match_value_or_fail(digestResp, "qop", "auth");
1661 f_sip_param_match_value_or_fail(digestResp, "nc", "00000001");
1662 f_sip_param_match_value_or_fail(digestResp, "cnonce", f_sip_str_quote("0a4f113b"));
1663 f_sip_param_match_value_or_fail(digestResp, "response", f_sip_str_quote("6629fae49393a05397450978507c4ef1"));
1664 f_sip_param_match_value_or_fail(digestResp, "opaque", f_sip_str_quote("5ccc069c403ebaf9f0171e9517f40e41"));
1665}
1666
Pau Espin Pedrol6052a342024-03-28 20:20:46 +01001667/* RFC 3261 8.1.1.5:
1668 * "The sequence number value MUST be expressible as a 32-bit unsigned integer
1669 * and MUST be less than 2**31."
1670 */
1671function f_sip_rand_seq_nr() return integer {
1672 /* 2**31 = 2147483648 */
1673 return f_rnd_int(2147483648)
1674}
Harald Welteb0d93602018-03-20 18:09:34 +01001675
Pau Espin Pedrol7011bf42024-04-08 17:56:58 +02001676function f_sip_next_seq_nr(integer seq_nr) return integer {
1677 return (seq_nr + 1) mod 2147483648;
1678}
1679
1680function f_sip_Request_inc_seq_nr(inout template (value) PDU_SIP_Request req) {
1681 req.msgHeader.cSeq.seqNumber := f_sip_next_seq_nr(valueof(req.msgHeader.cSeq.seqNumber));
1682}
1683
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001684function f_sip_rand_tag() return charstring {
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001685 /* Tags shall have at least 32 bit of randomness */
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001686 var integer rnd_int := f_rnd_int(4294967296);
Pau Espin Pedrol95ad6a02024-04-18 16:52:46 +02001687 /* Make collisions harder by appending time to the final string: */
1688 var integer ts_int := f_time_ms() mod 4294967296;
1689 return hex2str(int2hex(rnd_int, 8)) & "-" & hex2str(int2hex(ts_int, 8));
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001690}
1691
1692/* Generate a "branch" tag value.
1693 * RFC 3261 p.105 section 8:
1694 * "A common way to create this value is to compute a
1695 * cryptographic hash of the To tag, From tag, Call-ID header
1696 * field, the Request-URI of the request received (before
1697 * translation), the topmost Via header, and the sequence number
1698 * from the CSeq header field, in addition to any Proxy-Require
1699 * and Proxy-Authorization header fields that may be present. The
1700 * algorithm used to compute the hash is implementation-dependent,
1701 * but MD5 (RFC 1321 [35]),expressed in hexadecimal, is a reasonable
1702 * choice."
1703 * See also Section 8.1.1.7:
1704 * "The branch ID inserted by an element compliant with this
1705 * specification MUST always begin with the characters "z9hG4bK"."
1706 */
1707const charstring sip_magic_cookie := "z9hG4bK";
1708function f_sip_gen_branch(charstring tag_to,
1709 charstring tag_from,
1710 charstring tag_call_id,
1711 integer cseq) return charstring {
1712 var charstring str := tag_to & tag_from & tag_call_id & int2str(cseq);
1713 var charstring hash := f_calculateMD5(str);
1714 var charstring branch := sip_magic_cookie & hash;
1715 return branch;
1716}
1717
1718function f_sip_HostPort_to_str(HostPort host_port) return charstring {
1719 var charstring str := "";
1720 if (ispresent(host_port.host)) {
1721 str := host_port.host;
1722 }
1723 if (ispresent(host_port.portField)) {
1724 str := str & ":" & int2str(host_port.portField);
1725 }
1726 return str;
1727}
1728
1729function f_sip_SipUrl_to_str(SipUrl uri) return charstring {
Pau Espin Pedrolb0dbf7a2024-05-22 18:12:15 +02001730 var charstring str := uri.scheme & ":";
1731 if (ispresent(uri.userInfo)) {
1732 str := str & uri.userInfo.userOrTelephoneSubscriber & "@";
1733 }
1734 str := str & f_sip_HostPort_to_str(uri.hostPort);
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001735 return str;
1736}
1737
1738function f_sip_NameAddr_to_str(NameAddr naddr) return charstring {
1739 if (ispresent(naddr.displayName)) {
1740 return naddr.displayName & " <" & f_sip_SipUrl_to_str(naddr.addrSpec) & ">";
1741 } else {
1742 return f_sip_SipUrl_to_str(naddr.addrSpec);
1743 }
1744}
1745
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001746function f_sip_Addr_Union_to_str(Addr_Union addru) return charstring {
1747 if (ischosen(addru.nameAddr)) {
1748 return f_sip_NameAddr_to_str(addru.nameAddr);
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001749 } else {
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001750 return f_sip_SipUrl_to_str(addru.addrSpecUnion);
Pau Espin Pedrol05eaa1a2024-04-02 12:56:26 +02001751 }
1752}
1753
Pau Espin Pedrol41b0e072024-05-29 18:25:51 +02001754function f_sip_SipAddr_to_str(SipAddr sip_addr) return charstring {
1755 return f_sip_Addr_Union_to_str(sip_addr.addr);
1756}
1757
Harald Welteb0d93602018-03-20 18:09:34 +01001758}